管道
MongoDB聚合管道由多个阶段组成。每个阶段在文档通过管道时转换文档。管道阶段不需要为每个输入文档生成一个输出文档;例如,有些阶段可能会生成新的文档或过滤掉文档。
管道阶段可以在管道中出现多次,但$out
、$merge
和$geoNear
阶段除外。有关所有可用阶段的列表,请参见聚合管道阶段。
MongoDB在mongo shell中提供db.collection.aggregate()方法和用于运行聚合管道的聚合命令。
例如,聚合管道的使用,请考虑使用用户首选项数据和邮政编码数据集进行聚合。
从MongoDB 4.2开始,你可以使用聚合管道更新:
命令 | mongo Shell的方法 |
---|---|
findAndModify | db.collection.findOneAndUpdate() db.collection.findAndModify() |
update | db.collection.updateOne() db.collection.updateMany() db.collection.update() Bulk.find.update() Bulk.find.updateOne() Bulk.find.upsert() |
管道表达式
有些管道阶段采用管道表达式作为操作数。管道表达式指定应用于输入文档的转换。表达式具有文档结构,可以包含其他表达式。
管道表达式只能对管道中的当前文档进行操作,不能引用其他文档中的数据:表达式操作提供了文档在内存中的转换。
通常,表达式是无状态的,只有在聚合过程看到表达式时才会计算,只有一个例外:累加器表达式。
在$group
阶段中使用的累加器在记录管道中的进程时维护它们的状态(例如总数、最大值、最小值和相关数据)。
3.2版本的变化:一些累加器在$project
阶段可用;但是,在$project
阶段使用时,累加器不会跨文档维护它们的状态。
有关表达式的更多信息,请参见表达式。
聚合管道的行为
在MongoDB中,聚合命令对单个集合进行操作,在逻辑上将整个集合传递到聚合管道中。为了优化操作,尽可能使用以下策略来避免扫描整个集合。
管道操作符和索引
MongoDB的查询规划器通过分析聚合管道来确定是否可以使用索引来提高管道性能。例如,下面的管道阶段可以利用索引:
下面的管道阶段并不是可以使用索引的所有阶段的完整列表。
$match
如果文档发生在管道的开头,则$match
阶段可以使用索引来筛选文档。$sort
只要前面没有$project
、$unwind
或$group
阶段,$sort
阶段就可以使用索引。$group
如果符合以下所有条件,$group
阶段有时可以使用索引查找每组中的第一个文档:$geoNear
$geoNear
管道操作符利用地理空间索引。在使用$geoNear
时,$geoNear
管道操作必须作为聚合管道的第一阶段出现。
3.2版本中的变化:从MongoDB 3.2开始,索引可以覆盖聚合管道。在MongoDB 2.6和3.0中,索引不能覆盖聚合管道,因为即使管道使用索引,聚合仍然需要访问实际的文档。
早期的过滤
如果聚合操作只需要集合中数据的一个子集,则使用$match
、$limit
和$skip
阶段来限制在管道开头输入的文档。当放在管道的开头时,$match操作使用合适的索引只扫描集合中匹配的文档。
在管道开始处放置一个$match
管道阶段和一个$sort
阶段,在逻辑上等同于一个带有排序的查询,并且可以使用索引。如果可能,在管道的开头放置$match
操作符。
注意事项
分片集合
聚合管道支持对分片集合的操作。请参阅聚合管道和分片集合。
Aggregation vs Map-Reduce
聚合管道为map-reduce提供了一种替代方案,并且对于map-reduce的复杂性可能没有保障的聚合任务,它可能是首选的解决方案。
局限
聚合管道对值类型和结果大小有一些限制。有关聚合管道的限制和限制的详细信息,请参见聚合管道限制。
管道优化
聚合管道有一个内部优化阶段,为某些操作符序列提供改进的性能。有关详细信息,请参见聚合管道优化。