Docs 菜单
Docs 主页
/
MongoDB Manual
/ / /

db.collection.aggregate()

在此页面上

  • 定义
  • 兼容性
  • 语法
  • 行为
  • 示例

带有驱动程序的 MongoDB

本页介绍了 mongosh方法。要查看 MongoDB 驱动程序中的等效方法,请参阅您的编程语言的相应页面:

C#Java SyncNode.jsCC++GoJava RSKotlin CoroutineKotlin SyncPHPMotorPyMongoMongoidRustScalaSwift
db.collection.aggregate(pipeline, options)

计算集合或视图中数据的聚合值。

返回:
  • 在聚合分析管道的最后阶段生成的文档游标
  • 如果管道包含 explain 选项,查询将返回一个详细说明聚合操作处理的文档。
  • 如果管道包含 $out$merge 操作符,查询将返回一个空游标。

可以使用 db.collection.aggregate() 查找托管在以下环境中的部署:

aggregate() 方法采用以下形式:

db.collection.aggregate( <pipeline>, <options> )

aggregate() 方法使用以下参数:

Parameter
类型
说明
pipeline
阵列

一系列数据聚合操作或阶段。 See the aggregation pipeline operators for details.

该方法仍然可以接受管道阶段作为单独的参数,而不是作为数组中的元素;但是,如果您未将 pipeline 指定为数组,则无法指定 options 参数。

options
文档
可选。 aggregate()传递给aggregate命令的其他选项。 仅当您将pipeline指定为数组时才可用。 要查看可用选项,请参阅 AggregateOptions。

如果出现错误,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 选项。

  • 对于在 ACID 事务外部创建的游标,无法在 ACID 事务内部调用 getMore

  • 对于在事务中创建的游标,无法在事务外部调用 getMore

重要

在大多数情况下,与单文档写入操作相比,分布式事务会产生更高的性能成本,并且分布式事务的可用性不应取代有效的模式设计。在许多情况下,非规范化数据模型(嵌入式文档和数组)仍然是数据和使用案例的最佳选择。换言之,对于许多场景,适当的数据建模将最大限度地减少对分布式事务的需求。

有关其他事务使用注意事项(如运行时间限制和 oplog 大小限制),另请参阅生产注意事项

对于不包含 $out$merge 阶段的 db.collection.aggregate() 操作:

从 MongoDB 4.2 开始,如果在操作完成之前,发出 db.collection.aggregate() 的客户端断开连接,MongoDB 将使用killOpdb.collection.aggregate() 标记为终止。

8.0版本新增

您可以使用查询设置 来设立索引提示、设立操作拒绝筛选器和其他字段。这些设置应用于整个集群上的查询结构。集群在关闭后会保留这些设置。

查询优化器在查询规划期间将查询设置用作附加输入,这会影响为运行查询而选择的计划。您还可以使用查询设置来区块查询结构。

要添加查询设置并探索示例,请参阅setQuerySettings

您可以为finddistinctaggregate命令添加查询设置。

查询设置具有更多功能,并且比已弃用的索引筛选器更受青睐。

要删除查询设置,请使用 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 输出文档的目标读者是人类,而不是机器,并且输出格式因版本而不同。

您可以将 executionStatsallPlansExecution 解释模式传递给 db.collection.explain() 方法,以查看更详细的解释输出。

[1] 索引筛选器可能影响所用索引的选择。详情参见索引筛选器

从 MongoDB 6开始。 0 ,需要超过100 MB 内存才能执行的管道阶段,默认会将临时文件写入磁盘。这些临时文件在管道执行期间持续存在,可能会影响实例上的存储空间。在 MongoDB 的早期版本中,您必须将{ allowDiskUse: true }传递给各个findaggregate命令才能启用此行为。

单个findaggregate命令可以通过以下任一方式覆盖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 选项指定操作的读关注。

您不能将 $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 选项,以在 logsdb.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、客户端主机名和发出命令的用户。

版本 5.0 中的新增功能

要定义可在命令中其他位置访问的变量,请使用let选项。

注意

要通过在管道 $match 阶段使用变量筛选结果,必须访问 $expr 运算符中的变量。

创建包含不同口味蛋糕销售额的集合 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 } }
)

后退

集合