MongoDB中聚合(aggregate) 操做未来自多个document的value组合在一块儿,并经过对分组数据进行各类操做处理,并返回计算后的数据结果,主要用于处理数据(诸如统计平均值,求和等)。MongoDB提供三种方式去执行聚合操做:聚合管道(aggregation pipeline)、Map-Reduce函数以及单一的聚合命令(count、distinct、group)。mongodb
聚合管道是由aggregation framework将文档进入一个由多个阶段(stage)组成的管道,能够对每一个阶段的管道进行分组、过滤等功能,而后通过一系列的处理,输出相应的聚合结果。如图所示:数据库
聚合管道操做:数组
db.orders.aggregate([
{ $match: { status: "A" } },
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
复制代码
管道在Unix和Linux中通常用于将当前命令的输出结果做为下一个命令的参数,MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操做是能够重复的。
最基本的管道功能提供过滤器filter,其操做相似于查询和文档转换,能够修改输出文档的形式。 其余管道操做提供了按特定字段或字段对文档进行分组和排序的工具,以及用于聚合数组内容(包括文档数组)的工具。 此外,管道阶段可使用运算符执行任务,例如计算平均值或链接字符串。总结以下:函数
管道操做符工具
经常使用管道 | 解析 |
---|---|
$group | 将collection中的document分组,可用于统计结果 |
$match | 过滤数据,只输出符合结果的文档 |
$project | 修改输入文档的结构(例如重命名,增长、删除字段,建立结算结果等) |
$sort | 将结果进行排序后输出 |
$limit | 限制管道输出的结果个数 |
$skip | 跳过制定数量的结果,而且返回剩下的结果 |
$unwind | 将数组类型的字段进行拆分 |
表达式操做符学习
经常使用表达式 | 含义 |
---|---|
$sum | 计算总和,{$sum: 1}表示返回总和×1的值(即总和的数量),使用{$sum: '$制定字段'}也能直接获取制定字段的值的总和 |
$avg | 求平均值 |
$min | 求min值 |
$max | 求max值 |
$push | 将结果文档中插入值到一个数组中 |
$first | 根据文档的排序获取第一个文档数据 |
$last | 同理,获取最后一个数据 |
为了便于理解,将常见的mongo的聚合操做和MySql的查询作类比:优化
MongoDB聚合操做 | MySql操做/函数 |
---|---|
$match | where |
$group | group by |
$match | having |
$project | select |
$sort | order by |
$limit | limit |
$sum | sum() |
$lookup | join |
管道序列优化化:
1).使用$projector/$addFields+$match 序列优化:当Aggregation Pipeline中有多个$projectior/$addFields阶段和$match 阶段时,会先执行有依赖的$projector/$addFields阶段,而后会新建立的$match阶段执行,以下,spa
{ $addFields: {
maxTime: { $max: "$times" },
minTime: { $min: "$times" }
} },
{ $project: {
_id: 1, name: 1, times: 1, maxTime: 1, minTime: 1,
avgTime: { $avg: ["$maxTime", "$minTime"] }
} },
{ $match: {
name: "Joe Schmoe",
maxTime: { $lt: 20 },
minTime: { $gt: 5 },
avgTime: { $gt: 7 }
} }
复制代码
优化执行:code
{ $match: { name: "Joe Schmoe" } },
{ $addFields: {
maxTime: { $max: "$times" },
minTime: { $min: "$times" }
} },
{ $match: { maxTime: { $lt: 20 }, minTime: { $gt: 5 } } },
{ $project: {
_id: 1, name: 1, times: 1, maxTime: 1, minTime: 1,
avgTime: { $avg: ["$maxTime", "$minTime"] }
} },
{ $match: { avgTime: { $gt: 7 } } }
复制代码
2). $sort + $match 以及$project + $skip,当$sort/$project跟在$match/$skip以后时,会先执行$match/$skip后再执行$sort/$project,$sort以达到最小化需排列的对象数,$skip约束,以下:cdn
{ $sort: { age : -1 } },
{ $match: { score: 'A' } }
{ $project: { status: 1, name: 1 } },
{ $skip: 5 }
复制代码
优化执行:
{ $match: { score: 'A' } },
{ $sort: { age : -1 } }
{ $skip: 5 },
{ $project: { status: 1, name: 1 } }
复制代码
3). $redact+$match序列优化,当$redact后有$match时,可能会新创一个$match阶段进行优化,以下,
{ $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
{ $match: { year: 2014, category: { $ne: "Z" } } }
复制代码
优化执行:
{ $match: { year: 2014 } },
{ $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
{ $match: { year: 2014, category: { $ne: "Z" } } }
复制代码
还有不少管道序列优化能够查看《官方文档-Aggregation Pipeline Optimization》。
若是管道以$match精确分片 key开始的后,全部管道会在匹配的分片上进行。对于需运行在多分片中的聚合(aggregation)操做,若是不不须要在主分片进行的,这些操做后的结果会路由到随机分片中进行合并结果,避免重载该主分片的数据库。$out和$look阶段必须在主分片数据库运行。
MongoDB还提供map-reduce操做来执行聚合。 一般,map-reduce操做有两个阶段:一个map阶段,它处理每一个文档并为每一个输入文档发出一个或多个对象,以及reduce阶段组合map操做的输出。 可选地,map-reduce能够具备最终化阶段以对结果进行最终修改。 与其余聚合操做同样,map-reduce能够指定查询条件以选择输入文档以及排序和限制结果。
Map-reduce使用自定义JavaScript函数来执行映射和减小操做,以及可选的finalize操做。 虽然自定义JavaScript与聚合管道相比提供了极大的灵活性,但一般,map-reduce比聚合管道效率更低,更复杂。模式以下:
MongoDB还提供了,db.collection.estimatedDocumentCount(),db.collection.count()和db.collection.distinct() 全部这些单一的聚合命令。 虽然这些操做提供了对常见聚合过程的简单访问操做,但它们缺少聚合管道和map-reduce的灵活性和功能。模型以下
可以使用MongoDB中聚合操做用于数据处理,能够适应于一些数据分析等,聚合的典型应用包括销售数据的业务报表,好比将各地区的数据分组后计算销售总和、财务报表等。最后想要更加深刻理解还须要本身去实践。
最后可关注公众号,一块儿学习,天天会分享干货,还有学习视频干货领取!