51.MongoDB聚合操作与索引使用详解

聚合操作

聚合操作允许用户处理多个文档并返回计算结果。

从效果而言,聚合框架相当于 SQL 查询中的GROUP BY、 LEFT OUTER JOIN 、 AS等。

聚合管道

整个聚合运算过程称为管道(Pipeline),由多个阶段(Stage)组成

原始数据集 -----------Stage---------》中间结果 ------------Stage--------》中间结果 --------------------》结果集

常用的聚合阶段运算符

  • $match 筛选条件
  • $project 投影
  • $lookup 左外连接
  • $sort 排序
  • $group 分组
    • g r o u p 阶段的内存限制为 100 M 。默认情况下,如果 s t a g e 超过此限制, group阶段的内存限制为100M。默认情况下,如果stage超过此限制, group阶段的内存限制为100M。默认情况下,如果stage超过此限制,group将产生错误。但是,要允许处理大型数据集,请将allowDiskUse选项设置为true以启用$group操作以写入临时文件。
  • s k i p / skip/ skip/limit 分页
  • $unwind 展开数组
  • $graphLookup 图搜索
    • 主要用来实现多表关联查询, 相当关系型数据库中多表关联查询。
  • f a c e t / facet/ facet/bucket 分面搜索
#投影操作,将原始字段投影成指定名称,可以灵活控制输出文档的格式
db.books.aggregate([{$project:{name:"$title",_id:0,type:1,author:1}}])

#$match用于对文档进行筛选,尽可能将$match放在管道的前面位置,可以使用索引,过滤掉不需要的文档
db.books.aggregate([{$match:{type:"technology"}}])
#type:0导致的错误 Invalid $project :: caused by :: Cannot do exclusion on field type in inclusion projection
#$match和$project结合
db.books.aggregate([
    {$match:{type:"technology"}},
    {$project:{name:"$title",_id:0,type:1,author:{name:1}}}
])

#$count
db.books.aggregate([
    {$match:{type:"technology"}},
    {$count: "type_count"}
])

#$group 
#accumulator操作符 $avg $first $last $max $min $push $addToSet $sum $stdDevPop $stdDevSamp
#book的数量,收藏总数和平均值
db.books.aggregate([
    {$group:{_id:null,count:{$sum:1},pop:{$sum:"$favCount"},avg:{$avg:"$favCount"}}}
])
#统计每个作者的book收藏总数
db.books.aggregate([
    {$group:{_id:"$author.name",pop:{$sum:"$favCount"}}}
])
#统计每个作者的每本book的收藏数
db.books.aggregate([
    {$group:{_id:{name:"$author.name",title:"$title"},pop:{$sum:"$favCount"}}}
])
#每个作者的book的type合集
db.books.aggregate([
    {$group:{_id:"$author.name",types:{$addToSet:"$type"}}}
])
#姓名为xx006的作者的book的tag数组拆分为多个文档
db.books.aggregate([
    {$match:{"author.name":"xx006"}},
    {$unwind:"$tag"}
])

#每个作者的book的tag合集
db.books.aggregate([
    {$unwind:"$tag"},
    {$group:{_id:"$author.name",types:{$addToSet:"$tag"}}}
])
# 使用includeArrayIndex选项来输出数组元素的数组索引
db.books.aggregate([
    {$match:{"author.name":"fox"}},
    {$unwind:{path:"$tag", includeArrayIndex: "arrayIndex"}}
])
# 使用preserveNullAndEmptyArrays选项在输出中包含缺少size字段,null或空数组的文档,防止漏掉文档
db.books.aggregate([
    {$match:{"author.name":"fox"}},
    {$unwind:{path:"$tag", preserveNullAndEmptyArrays: true}}
])

#$limit 限制传递到管道中下一阶段的文档数
db.books.aggregate([
    {$limit : 5 }
])

#$skip 跳过进入stage的指定数量的文档,并将其余文档传递到管道中的下一个阶段
db.books.aggregate([
     {$skip : 50 }
])

#$sort 对所有输入文档进行排序,并按排序顺序将它们返回到管道。
db.books.aggregate([
	{$skip : 50 }
    {$sort : {favCount:-1,"author.age":1}}
])

#$lookup 每个输入待处理的文档,经过$lookup 阶段的处理,输出的新文档中会包含一个新生成的数组

db.customer.aggregate([        
    {$lookup: {
       from: "order",
       localField: "customerCode",
       foreignField: "customerCode",
       as: "customerOrder"
     }
    } 
])
db.order.aggregate([
    {$lookup: {
               from: "customer",
               localField: "customerCode",
               foreignField: "customerCode",
               as: "curstomer"
             }
        
    },
    {$lookup: {
               from: "orderItem",
               localField: "orderId",
               foreignField: "orderId",
               as: "orderItem"
             }
    }
])


#标签的热度排行,标签的热度则按其关联book文档的收藏数(favCount)来计算
db.books.aggregate([
    {$match:{favCount:{$gt:0}}},
    {$unwind:"$tag"},
    {$group:{_id:"$tag",total:{$sum:"$favCount"}}},
    {$sort:{total:-1}}
])


#$bucket
db.books.aggregate([{
    $bucket:{
        groupBy:"$favCount",
        boundaries:[0,10,60,80,100],
        default:"other",
        output:{"count":{$sum:1}}
    }
}])


#使用mongoimport工具导入数据
mongoimport -h 192.168.139.150 -d test -u lywtimer -p 0918 --authenticationDatabase=admin -c zips --file D:\mongodb-database-tools-windows-x86_64-100.9.0\zips.json  

#返回人口超过1000万的州
db.zips.aggregate( [
   { $group: { _id: "$state", totalPop: { $sum: "$pop" } } },
   { $match: { totalPop: { $gte: 10*1000*1000 } } }
] )




聚合优化

  • 尽可能利用索引完成搜索和排序
  • 尽早尽多减少数据量
  • 尽可能减少执行步骤

MongoDB索引详解

MongoDB采用B+Tree 做索引,索引创建colletions上。

索引类型

  • 单键索引
  • 复合索引
  • 多键(数组)索引
  • Hash索引
  • 地理空间索引
  • 全文索引
  • 通配符索引
    • MongoDB的文档模式是动态变化的,而通配符索引可以建立在一些不可预知的字段上,以此实现查询的加速。MongoDB 4.2 引入了通配符索引来支持对未知或任意字段的查询。

索引属性

  • 唯一索引
  • 部分索引
  • 稀疏索引
  • TTL索引
  • 隐藏索引
    • 通过对规划器隐藏索引,用户可以在不实际删除索引的情况下评估删除索引的潜在影响。如果影响是负面的,用户可以取消隐藏索引,而不必重新创建已删除的索引。

索引使用建议

  • 为每一个查询建立合适的索引
  • 创建合适的复合索引,不要依赖于交叉索引
  • 复合索引字段顺序:匹配条件在前,范围条件在后
  • 尽可能使用覆盖索引
  • 建索引要在后台运行
  • 避免设计过长的数组索引
# 创建单键索引
db.books.createIndex({title:1})
# 对内嵌文档字段创建索引:
db.books.createIndex({"author.name":1})
# 创建复合索引
db.books.createIndex({type:1,favCount:1})
#查看执行计划  winningPlan: {stage: 'COLLSCAN'    winningPlan: {stage: 'FETCH'
db.books.find({type:"novel",favCount:{$gt:50}}).explain()
#查看索引信息
db.books.getIndexes()
#查看索引键
db.books.getIndexKeys()
#删除集合指定索引
db.col.dropIndex("索引名称")
#删除集合所有索引   不能删除主键索引
db.col.dropIndexes()
#创建 hash 索引
db.users.createIndex({username : 'hashed'})
#地理空间索引(2dsphereindex)就是专门用于实现位置检索的一种特殊索引
db.restaurant.createIndex({location : "2dsphere"})
#全文检索
db.reviews.createIndex( { comments: "text" } )
#通配符索引
db.products.createIndex( { "product_attributes.$**" : 1 } )
# 复合索引支持唯一性约束
db.values.createIndex({title:1,type:1},{unique:true})
#部分索引仅对满足指定过滤器表达式的文档进行索引
db.restaurants.createIndex(
   { cuisine: 1, name: 1 },
   { partialFilterExpression: { rating: { $gt: 5 } } }
)
#不索引不包含xmpp_id字段的文档
db.addresses.createIndex( { "xmpp_id": 1 }, { sparse: true } )
# 创建 TTL 索引,TTL 值为3600秒
db.eventlog.createIndex( { "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 } )
#创建隐藏索引
db.restaurants.createIndex({ borough: 1 },{ hidden: true });
# 隐藏现有索引
db.restaurants.hideIndex( { borough: 1} );
db.restaurants.hideIndex( "索引名称" )
# 取消隐藏索引
db.restaurants.unhideIndex( { borough: 1} );
db.restaurants.unhideIndex( "索引名称" ); 

你可能感兴趣的:(726打卡,mongodb,线性代数,数据库)