db.collection.aggregate()
带有驱动程序的 MongoDB
本页介绍了 mongosh
方法。要查看 MongoDB 驱动程序中的等效方法,请参阅您的编程语言的相应页面:
定义
db.collection.aggregate(pipeline, options)
计算集合或视图中数据的聚合值。
返回:
兼容性
可以使用 db.collection.aggregate()
查找托管在以下环境中的部署:
MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
aggregate()
方法采用以下形式:
db.collection.aggregate( <pipeline>, <options> )
aggregate()
方法使用以下参数:
Parameter | 类型 | 说明 |
---|---|---|
pipeline | 阵列 | 一系列数据聚合操作或阶段。 See the aggregation pipeline operators for details. 该方法仍然可以接受管道阶段作为单独的参数,而不是作为数组中的元素;但是,如果您未将 |
options | 文档 |
行为
Error Handling
如果出现错误,aggregate()
辅助程序会抛出异常。
游标行为
在mongosh
中,如果从db.collection.aggregate()
返回的游标未赋值给使用var
关键字的变量,则mongosh
会自动迭代游标最多20次。 有关在 mongosh
中处理游标的信息,请参阅在mongosh
中迭代游标
聚合返回的游标只支持对已评估游标进行操作的游标方法(即第一批已检索到的游标),如以下方法:
有关更多信息,请参阅:
会话
对于在一个会话内创建的游标,不能在该会话外调用 getMore
。
同样,对于在会话外创建的游标,不能在会话内调用 getMore
。
会话空闲超时
MongoDB 驱动程序和 mongosh
将所有操作与服务器会话相关联,未确认的写入操作除外。对于未与会话显式关联的操作(即使用 Mongo.startSession()
),MongoDB 驱动程序和 mongosh
会创建隐式会话并将其与该操作关联。
如果会话空闲时间超过 30 分钟,MongoDB Server 会将该会话标记为已过期,并可能随时将其关闭。当 MongoDB Server 关闭会话时,它还会终止任何正在进行的操作并打开与会话关联的游标。这包括使用超过 30 分钟的 noCursorTimeout()
或 maxTimeMS()
配置的游标。
对于返回游标的操作,如果游标的空闲时间可能超过 30 分钟,则使用 Mongo.startSession()
在显式会话中发出操作,并使用 refreshSessions
命令定期刷新会话。更多信息,请参阅会话空闲超时。
事务
db.collection.aggregate()
可以在分布式事务中使用。
但是,事务中不允许有以下阶段:
此外,您不能指定 explain
选项。
重要
在大多数情况下,与单文档写入操作相比,分布式事务会产生更高的性能成本,并且分布式事务的可用性不应取代有效的模式设计。在许多情况下,非规范化数据模型(嵌入式文档和数组)仍然是数据和使用案例的最佳选择。换言之,对于许多场景,适当的数据建模将最大限度地减少对分布式事务的需求。
有关其他事务使用注意事项(如运行时间限制和 oplog 大小限制),另请参阅生产注意事项。
客户端断开连接
对于不包含 $out
或 $merge
阶段的 db.collection.aggregate()
操作:
从 MongoDB 4.2 开始,如果在操作完成之前,发出 db.collection.aggregate()
的客户端断开连接,MongoDB 将使用killOp
将 db.collection.aggregate()
标记为终止。
查询设置
8.0版本新增。
您可以使用查询设置 来设立索引提示、设立操作拒绝筛选器和其他字段。这些设置应用于整个集群上的查询结构。集群在关闭后会保留这些设置。
查询优化器在查询规划期间将查询设置用作附加输入,这会影响为运行查询而选择的计划。您还可以使用查询设置来区块查询结构。
要添加查询设置并探索示例,请参阅setQuerySettings
。
您可以为find
、 distinct
和aggregate
命令添加查询设置。
查询设置具有更多功能,并且比已弃用的索引筛选器更受青睐。
要删除查询设置,请使用 removeQuerySettings
。要获取查询设置,请在一个聚合管道中使用一个 $querySettings
阶段。
示例
以下示例使用包含以下文档的集合 orders
:
db.orders.insertMany( [ { _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 }, { _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 }, { _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 }, { _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 }, { _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 } ] )
分组并计算总和
以下聚合操作选择状态等于 "A"
的文档,按 cust_id
字段对匹配文档进行分组,并根据 amount
字段的总和计算每个 cust_id
字段的 total
,并对结果按 total
字段降序排列:
db.orders.aggregate( [ { $match: { status: "A" } }, { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }, { $sort: { total: -1 } } ] )
该操作返回一个包含以下文档的游标:
[ { _id: "xyz1", total: 100 }, { _id: "abc1", total: 75 } ]
mongosh
自动遍历返回的游标,以打印结果。请参阅在 mongosh
中遍历游标以在 mongosh
中手动处理游标。
返回聚合管道操作信息
以下示例使用 db.collection.explain()
查看聚合管道执行计划的详细信息。
db.orders.explain().aggregate( [ { $match: { status: "A" } }, { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }, { $sort: { total: -1 } } ] )
该操作返回一个文档,其中详细说明了聚合管道的处理过程。例如,除其他详细信息外,文档还可以显示该操作使用的索引(如果有)。 [ 1 ]如果orders
集合是分片集合,则文档还会显示分片和合并操作之间的分工,以及针对定向查询的目标分片。
注意
explain
输出文档的目标读者是人类,而不是机器,并且输出格式因版本而不同。
您可以将 executionStats
或 allPlansExecution
解释模式传递给 db.collection.explain()
方法,以查看更详细的解释输出。
[1] | 索引筛选器可能影响所用索引的选择。详情参见索引筛选器。 |
互动 allowDiskUseByDefault
从 MongoDB 6开始。 0 ,需要超过100 MB 内存才能执行的管道阶段,默认会将临时文件写入磁盘。这些临时文件在管道执行期间持续存在,可能会影响实例上的存储空间。在 MongoDB 的早期版本中,您必须将{ allowDiskUse: true }
传递给各个find
和aggregate
命令才能启用此行为。
单个find
和aggregate
命令可以通过以下任一方式覆盖allowDiskUseByDefault
参数:
使用
{ allowDiskUse: true }
以允许在allowDiskUseByDefault
设置为false
时将临时文件写入磁盘使用
{ allowDiskUse: false }
以禁止在allowDiskUseByDefault
设置为true
时将临时文件写入磁盘
如果聚合阶段因为内存限制而写入临时文件,则分析器日志消息和诊断日志消息包含一个 usedDisk
指示器。
有关更多信息,请参阅聚合管道限制。
指定初始批次大小
要指定游标的初始批次大小,请对 cursor
选项使用以下语法:
cursor: { batchSize: <int> }
例如,以下聚合操作指定游标的初始批处理大小为 0
:
db.orders.aggregate( [ { $match: { status: "A" } }, { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }, { $sort: { total: -1 } }, { $limit: 2 } ], { cursor: { batchSize: 0 } } )
{ cursor: { batchSize: 0 } }
文档指定初始批处理大小,表示首次批处理为空。此批处理大小对于快速返回游标或失败消息非常有用,无需执行大量服务器端工作。
要为后续 getMore
操作(初始批次后)指定批次大小,请在运行 getMore
命令时使用 batchSize
字段。
mongosh
自动遍历返回的游标,以打印结果。请参阅在 mongosh
中遍历游标以在 mongosh
中手动处理游标。
指定排序规则
排序规则允许用户为字符串比较指定特定于语言的规则,例如字母大小写和重音符号规则。
集合 restaurants
包含以下文档:
db.restaurants.insertMany( [ { _id: 1, category: "café", status: "A" }, { _id: 2, category: "cafe", status: "a" }, { _id: 3, category: "cafE", status: "a" } ] )
下面的聚合操作包括排序规则选项:
db.restaurants.aggregate( [ { $match: { status: "A" } }, { $group: { _id: "$category", count: { $sum: 1 } } } ], { collation: { locale: "fr", strength: 1 } } );
注意
如果执行的聚合涉及多个视图,例如使用 $lookup
或 $graphLookup
,则这些视图必须采用相同的排序规则。
有关排序规则字段的说明,请参阅排序规则文档。
提示索引
使用以下文档创建集合 food
:
db.food.insertMany( [ { _id: 1, category: "cake", type: "chocolate", qty: 10 }, { _id: 2, category: "cake", type: "ice cream", qty: 25 }, { _id: 3, category: "pie", type: "boston cream", qty: 20 }, { _id: 4, category: "pie", type: "blueberry", qty: 15 } ] )
创建以下索引:
db.food.createIndex( { qty: 1, type: 1 } ); db.food.createIndex( { qty: 1, category: 1 } );
下面的聚合操作包含 hint
选项,强制使用指定的索引:
db.food.aggregate( [ { $sort: { qty: 1 }}, { $match: { category: "cake", qty: 10 } }, { $sort: { type: -1 } } ], { hint: { qty: 1, category: 1 } } )
覆盖 readConcern
使用 readConcern
选项指定操作的读关注。
您不能将 $out
或 $merge
阶段与读关注 "linearizable"
一起使用。换言之,如果您为 db.collection.aggregate()
指定 "linearizable"
读关注,则不能在管道中包含任一阶段。
对副本集执行以下操作可以指定读关注 "majority"
,以读取确认已写入大多数节点的数据的最新副本。
注意
为确保单个线程可以读取自己的写入内容,请对副本集的主节点使用
"majority"
读关注和"majority"
写关注。您可以为包含
$out
阶段的聚合指定读关注级别"majority"
。无论读关注级别如何,节点上的最新数据可能无法反映系统中数据的最新版本。
db.restaurants.aggregate( [ { $match: { rating: { $lt: 5 } } } ], { readConcern: { level: "majority" } } )
指定备注
名为 movies
的集合包含以下格式的文档:
db.movies.insertOne( { _id: ObjectId("599b3b54b8ffff5d1cd323d8"), title: "Jaws", year: 1975, imdb: "tt0073195" } )
以下聚合操作可查找 1995 年制作的电影,并包含 comment
选项,以在 logs
、db.system.profile
集合和 db.currentOp
中提供跟踪信息。
db.movies.aggregate( [ { $match: { year : 1995 } } ], { comment : "match_all_movies_from_1995" } ).pretty()
在启用了分析的系统上,您可以查询 system.profile
集合以查看所有最近的类似聚合,如下所示:
db.system.profile.find( { "command.aggregate": "movies", "command.comment" : "match_all_movies_from_1995" } ).sort( { ts : -1 } ).pretty()
这将以下列格式返回一组剖析器结果:
{ "op" : "command", "ns" : "video.movies", "command" : { "aggregate" : "movies", "pipeline" : [ { "$match" : { "year" : 1995 } } ], "comment" : "match_all_movies_from_1995", "cursor" : { }, "$db" : "video" }, ... }
应用程序可以对注释中的任意信息进行编码,以便更轻松地跟踪或识别整个系统的特定操作。例如,应用程序可能会附加一个字符串注释,其中包含其进程 ID、线程 ID、客户端主机名和发出命令的用户。
使用以下项中的变量: let
版本 5.0 中的新增功能。
要定义可在命令中其他位置访问的变量,请使用let
选项。
创建包含不同口味蛋糕销售额的集合 cakeSales
:
db.cakeSales.insertMany( [ { _id: 1, flavor: "chocolate", salesTotal: 1580 }, { _id: 2, flavor: "strawberry", salesTotal: 4350 }, { _id: 3, flavor: "cherry", salesTotal: 2150 } ] )
如下示例:
检索
salesTotal
大于 3000 的蛋糕,即_id
为 2 的蛋糕在
let
中定义了一个targetTotal
变量,该变量在$gt
中被引用为$$targetTotal
db.cakeSales.aggregate( [ { $match: { $expr: { $gt: [ "$salesTotal", "$$targetTotal" ] } } } ], { let: { targetTotal: 3000 } } )