带驱动程序的 MongoDB
定义
兼容性
可以使用 db.collection.aggregate() 查找托管在以下环境中的部署:
- MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
db.collection.aggregate() 采用以下形式:
db.collection.aggregate( <pipeline>, <options> )
参数
db.collection.aggregate() 使用以下参数:
Parameter | 类型 | 说明 |
|---|---|---|
| 阵列 |
|
| 文档 | Optional. Additional options that |
行为
Error Handling
If an error occurs, the aggregate() helper throws an exception.
游标行为
在mongosh 中,如果未使用aggregate() var关键字将 游标分配给变量,则mongosh 会自动迭代游标,最多20 次。有关在 中处理游标的信息,请参阅在mongosh中迭代游标。mongosh
聚合返回的游标只支持对已评估游标进行操作的游标方法(即第一批已检索到的游标),如以下方法:
有关更多信息,请参阅:
会话
对于在一个会话内创建的游标,不能在该会话外调用 getMore。
同样,对于在会话外创建的游标,不能在会话内调用 getMore。
会话空闲超时
MongoDB drivers and mongosh associate all operations with a server session, with the exception of unacknowledged write operations. For operations not explicitly associated with a session (i.e. using Mongo.startSession()), MongoDB drivers and mongosh create an implicit session and associate it with the operation.
如果会话空闲时间超过 30 分钟,MongoDB Server 会将该会话标记为已过期,并可能随时将其关闭。当 MongoDB Server 关闭会话时,它还会终止任何正在进行的操作并打开与会话关联的游标。这包括使用超过 30 分钟的 noCursorTimeout() 或 maxTimeMS() 配置的游标。
对于返回游标的操作,如果游标的空闲时间可能超过 30 分钟,则使用 Mongo.startSession() 在显式会话中发出操作,并使用 refreshSessions 命令定期刷新会话。更多信息,请参阅会话空闲超时。
事务
aggregate() 可用于分布式事务。
但是,事务中不允许有以下阶段:
此外,您不能指定 explain 选项。
重要
在大多数情况下,与单文档写入操作相比,分布式事务会产生更高的性能成本,并且分布式事务的可用性不应取代有效的模式设计。在许多情况下,非规范化数据模型(嵌入式文档和数组)仍然是数据和使用案例的最佳选择。换言之,对于许多场景,适当的数据建模将最大限度地减少对分布式事务的需求。
有关其他事务使用注意事项(如运行时间限制和 oplog 大小限制),另请参阅生产注意事项。
客户端断开连接
对于不包含 $out 或 $merge 阶段的 aggregate() 操作:
如果发出 aggregate() 的客户端在操作完成之前断开连接,则MongoDB使用killOp将 aggregate() 标记为终止。
示例
以下示例使用包含以下文档的集合 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 iterates the returned cursor automatically to print the results. See Iterate a Cursor in mongosh for handling cursors manually in 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 兆字节以上内存容量的管道阶段默认将临时文件写入磁盘。这些临时文件在管道执行期间持续存在,并且可能影响实例上的存储空间。在 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 iterates the returned cursor automatically to print the results. See Iterate a Cursor in mongosh for handling cursors manually in mongosh.
指定排序规则
排序规则允许用户为字符串比较指定特定于语言的规则,例如字母大小写和重音符号规则。
集合 restaurants 包含以下文档:
db.restaurants.insertMany( [ { _id: 1, category: "café", status: "Open" }, { _id: 2, category: "cafe", status: "open" }, { _id: 3, category: "cafE", status: "open" } ] )
下面的聚合操作包括排序规则选项:
db.restaurants.aggregate( [ { $match: { status: "Open" } }, { $group: { _id: "$category", count: { $sum: 1 } } } ], { collation: { locale: "fr", strength: 1 } } )
[ { _id: 'café', count: 3 } ]
聚合指定带有 strength: 1 的排序规则,这意味着排序规则忽略大小写和字母变体之间的差异。因此:
$match过滤匹配集合中的所有文档,并将这些文档传递到$group阶段。$group阶段忽略category字段中字母变体的差异,并将所有文档放在一个群组中。
注意
如果执行的聚合涉及多个视图,例如使用 $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 选项指定操作的读关注。
You cannot use the $out or the $merge stage in conjunction with read concern "linearizable". That is, if you specify "linearizable" read concern for db.collection.aggregate(), you cannot include either stages in the pipeline.
对副本集执行以下操作可以指定读关注 "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 } } )