聚合
定义
aggregate
使用聚合管道执行聚合操作。管道允许用户通过一系列基于阶段的操作来处理集合或其他来源的数据。
提示
在
mongosh
中,此命令也可通过db.aggregate()
和db.collection.aggregate()
助手方法或watch()
助手方法来运行。辅助方法对
mongosh
用户来说很方便,但它们返回的信息级别可能与数据库命令不同。如果不追求方便或需要额外的返回字段,请使用数据库命令。
兼容性
此命令可用于以下环境中托管的部署:
MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
重要
此命令在 M 0 、 M 2和 M 5集群中提供有限支持。 有关更多信息,请参阅不支持的命令。
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
5.0 版本中的更改。
该命令的语法如下:
{ aggregate: "<collection>" || 1, pipeline: [ <stage>, <...> ], explain: <boolean>, allowDiskUse: <boolean>, cursor: <document>, maxTimeMS: <int>, bypassDocumentValidation: <boolean>, readConcern: <document>, collation: <document>, hint: <string or document>, comment: <any>, writeConcern: <document>, let: <document> // Added in MongoDB 5.0 }
命令字段
aggregate
命令将以下字段作为参数:
字段 | 类型 | 说明 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
aggregate | 字符串 | 充当聚合管道的输入的集合或视图的名称。使用 1 执行与集合无关的命令。 | ||||||||||
pipeline | 阵列 | 聚合管道阶段的数组,这些阶段将文档流作为聚合管道的一部分进行处理和转换。 | ||||||||||
explain | 布尔 | 可选。指定返回关于管道处理的信息。 不适用于多文档事务。 | ||||||||||
| 布尔 | |||||||||||
cursor | 文档 | 指定包含控制游标对象创建选项的文档。 MongoDB 删除了对不带
| ||||||||||
maxTimeMS | non-negative integer | 可选。 指定时间限制(以毫秒为单位)。如果您未指定 MongoDB 使用与 | ||||||||||
bypassDocumentValidation | 布尔 | |||||||||||
readConcern | 文档 | 可选。指定读关注。
可能的读关注级别是:
有关读关注级别的更多信息,请参阅读关注级别。
| ||||||||||
collation | 文档 | 可选。 指定用于操作的排序规则。 排序规则允许用户为字符串比较指定特定于语言的规则,例如字母大小写和重音符号规则。 排序规则选项的语法如下:
指定排序规则时, 如果未指定排序规则,但集合具有默认排序规则(请参阅 如果没有为收集或操作指定排序规则,MongoDB 将使用先前版本中使用的简单二进制比较来进行字符串比较。 您不能为一个操作指定多个排序规则。例如,您不能为每个字段指定不同的排序规则,或者如果执行带排序的查找,则不能使用一种排序规则进行查找而另一种排序规则进行排序。 版本 3.4 中的新增功能。 | ||||||||||
hint | 字符串或文档 | |||||||||||
comment | any | 可选。用户提供的待附加到该命令的注释。设置后,该注释将与该命令的记录一起出现在以下位置:
注释可以是任何有效的 BSON 类型(字符串、整型、对象、数组等)。 | ||||||||||
writeConcern | 文档 | |||||||||||
let | 文档 | 可选。 指定包含变量列表的文档。这样可以将变量与查询文本分开,从而提高命令的可读性。 文档语法为:
变量设置为表达式返回的值,并且之后不能再进行更改。 要访问命令中的变量值,请使用双美元符号前缀 ( 要使用变量筛选管道 有关使用 版本 5.0 中的新增功能。 |
MongoDB 删除了对不带 aggregate
选项的 cursor
命令的使用,该命令包含 explain
选项的情况除外。除非包含 explain
选项,否则必须指定游标选项。
要指示具有默认批次大小的游标,请指定
cursor: {}
。要指示具有非默认批次大小的游标,请使用
cursor: { batchSize: <num> }
。
会话
对于在一个会话内创建的游标,不能在该会话外调用 getMore
。
同样,对于在会话外创建的游标,不能在会话内调用 getMore
。
会话空闲超时
MongoDB 驱动程序和 mongosh
将所有操作与服务器会话相关联,未确认的写入操作除外。对于未与会话显式关联的操作(即使用 Mongo.startSession()
),MongoDB 驱动程序和 mongosh
会创建隐式会话并将其与该操作关联。
如果会话空闲时间超过 30 分钟,MongoDB Server 会将该会话标记为已过期,并可能随时将其关闭。当 MongoDB Server 关闭会话时,它还会终止任何正在进行的操作并打开与会话关联的游标。这包括使用超过 30 分钟的 noCursorTimeout()
或 maxTimeMS()
配置的游标。
对于返回游标的操作,如果游标的空闲时间可能超过 30 分钟,则使用 Mongo.startSession()
在显式会话中发出操作,并使用 refreshSessions
命令定期刷新会话。更多信息,请参阅会话空闲超时。
事务
但是,事务中不允许有以下阶段:
此外,您不能指定 explain
选项。
重要
在大多数情况下,与单文档写入操作相比,分布式事务会产生更高的性能成本,并且分布式事务的可用性不应取代有效的模式设计。在许多情况下,非规范化数据模型(嵌入式文档和数组)仍然是数据和使用案例的最佳选择。换言之,对于许多场景,适当的数据建模将最大限度地减少对分布式事务的需求。
有关其他事务使用注意事项(如运行时间限制和 oplog 大小限制),另请参阅生产注意事项。
客户端断开连接
对于不包含 $out
或 $merge
阶段的 aggregate
操作:
从 MongoDB 4.2 开始,如果在操作完成之前,发出 aggregate
的客户端断开连接,MongoDB 将使用killOp
将 aggregate
标记为终止。
Stable API
使用 Stable API V1 时:
您不能在
aggregate
命令中使用以下阶段:不要在
aggregate
命令中包含explain
字段。如果这样做,服务器将返回 APIStrictError 错误。使用
$collStats
阶段时,只能使用count
字段。没有其他可用的$collStats
字段。
例子
MongoDB 删除了对不带 aggregate
选项的 cursor
命令的使用,该命令包含 explain
选项的情况除外。除非包含 explain
选项,否则必须指定游标选项。
要指示具有默认批次大小的游标,请指定
cursor: {}
。要指示具有非默认批次大小的游标,请使用
cursor: { batchSize: <num> }
。
大多数用户应该使用 mongosh
提供的 db.collection.aggregate()
助手或驱动程序中的等效助手,而不是直接运行 aggregate
命令。在 2.6 及更高版本中,db.collection.aggregate()
助手始终会返回游标。
除演示命令语法的前两个示例外,本页中的其他示例均使用 db.collection.aggregate()
助手。
使用多阶段管道聚合数据
集合 articles
包含如下文档:
{ _id: ObjectId("52769ea0f3dc6ead47c9a1b2"), author: "abc123", title: "zzz", tags: [ "programming", "database", "mongodb" ] }
以下示例将对 articles
集合执行 aggregate
操作,以计算集合中出现的 tags
数组内每个不同元素的数量。
db.runCommand( { aggregate: "articles", pipeline: [ { $project: { tags: 1 } }, { $unwind: "$tags" }, { $group: { _id: "$tags", count: { $sum : 1 } } } ], cursor: { } } )
在 mongosh
中,该操作可以使用 db.collection.aggregate()
助手,如下所示:
db.articles.aggregate( [ { $project: { tags: 1 } }, { $unwind: "$tags" }, { $group: { _id: "$tags", count: { $sum : 1 } } } ] )
在管理员数据库上使用 $currentOp
以下示例将对管理员数据库上运行附带两个阶段的管道。第一个阶段会运行 $currentOp
操作,而第二个阶段则会筛选此操作的结果。
db.adminCommand( { aggregate : 1, pipeline : [ { $currentOp : { allUsers : true, idleConnections : true } }, { $match : { shard : "shard01" } } ], cursor : { } } )
注意
aggregate
命令不指定集合,而是采用 {aggregate: 1}
形式。这是因为初始 $currentOp
阶段不从集合中提取输入。它生成自己的数据,供管道其余部分使用。
添加了新的 db.aggregate()
助手,帮助运行类似本示例的无集合聚合。上述聚合也可以像这个示例一样运行。
返回聚合操作信息
以下聚合操作会将可选字段 explain
设为 true
以返回有关此聚合操作的信息。
db.orders.aggregate([ { $match: { status: "A" } }, { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }, { $sort: { total: -1 } } ], { explain: true } )
注意
解释输出可能因版本而异。
使用外部排序聚合数据
每个单独的管道阶段的 RAM 限制为100 MB 。 默认情况下,如果某个阶段超过此限制,MongoDB 会产生错误。 要允许管道处理占用更多空间,请将allowDiskUse选项设置为true
以允许将数据写入临时文件,如以下示例所示:
db.stocks.aggregate( [ { $sort : { cusip : 1, date: 1 } } ], { allowDiskUse: true } )
指定批处理大小的聚合数据
要指定初始批量大小,请在 cursor
字段中指定 batchSize
,如下面示例所示:
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
字段。
指定排序规则
版本 3.4 中的新增功能。
排序规则允许用户为字符串比较指定特定于语言的规则,例如字母大小写和重音符号规则。
集合 myColl
包含以下文档:
{ _id: 1, category: "café", status: "A" } { _id: 2, category: "cafe", status: "a" } { _id: 3, category: "cafE", status: "a" }
以下聚合操作包括排序规则选项:
db.myColl.aggregate( [ { $match: { status: "A" } }, { $group: { _id: "$category", count: { $sum: 1 } } } ], { collation: { locale: "fr", strength: 1 } } );
有关排序规则字段的说明,请参阅排序规则文档。
提示索引
版本 3.6 中的新增功能。
使用以下文档创建集合 foodColl
:
db.foodColl.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.foodColl.createIndex( { qty: 1, type: 1 } ); db.foodColl.createIndex( { qty: 1, category: 1 } );
下面的聚合操作包含 hint
选项,强制使用指定的索引:
db.foodColl.aggregate( [ { $sort: { qty: 1 }}, { $match: { category: "cake", qty: 10 } }, { $sort: { type: -1 } } ], { hint: { qty: 1, category: 1 } } )
覆盖默认读关注
若要覆盖默认的读关注级别,请使用 readConcern
选项。getMore
命令使用原始 aggregate
命令中指定的 readConcern
级别。
您不能将 $out
或 $merge
阶段与读关注 "linearizable"
一起使用。换言之,如果将 "linearizable"
读关注为 db.collection.aggregate()
指定,则不能在管道中包含任一阶段。
对副本集执行以下操作可以指定读关注 "majority"
,以读取确认已写入大多数节点的数据的最新副本。
重要
您可以为包含
$out
阶段的聚合指定读关注级别"majority"
。无论读关注级别如何,节点上的最新数据可能无法反映系统中数据的最新版本。
db.restaurants.aggregate( [ { $match: { rating: { $lt: 5 } } } ], { readConcern: { level: "majority" } } )
为确保单个线程可以读取自己的写入内容,请对副本集的主节点使用 "majority"
读关注和 "majority"
写关注。
使用以下项中的变量: 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.runCommand( { aggregate: db.cakeSales.getName(), pipeline: [ { $match: { $expr: { $gt: [ "$salesTotal", "$$targetTotal" ] } } }, ], cursor: {}, let: { targetTotal: 3000 } } )