对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

表达式、累加器和窗口函数

某些聚合操作符(例如 $avg、$sum 和 $max)出现在多个上下文中,每个上下文赋予操作符不同的行为。示例:

  • 作为表达式,$avg 返回数组中元素的平均值。

  • 作为累加器,$avg 返回一组文档中值的平均值。

  • 作为窗口函数,$avg 返回窗口中文档值的平均值。

包含操作符的阶段决定了其行为。同一个操作符名称可以接受不同的参数,并根据使用位置的不同返回不同的结果。本页面介绍了这三种上下文以及如何区分它们。

下图概念化了表达式、累加器和窗口函数的执行方式:

下表总结了这三种操作符类型的区别。

运算符类型
行为
适用场景

表达式(expression)

针对每个输入文档进行评估,并为每个文档返回一个值。

$project、$addFields 以及许多其他阶段,还有 $expr 谓词和 find 命令投影。

累加器

对一组输入文档进行聚合,并为每个组返回一个聚合值。

窗口函数

在输入文档的窗口上进行评估,并为每个文档返回一个值。

表达式会针对单个输入文档解析为一个值。表达式不会改变其输入。

表达式操作符接受一个参数数组,并具有以下通用形式:

{ <operator>: [ <argument1>, <argument2> ... ] }

如果操作符接受单个参数,则可以省略外部数组。

表达式也为累加器和窗口函数提供参数。示例,在 { $sum: "$price" } 中,字段路径(Field Path) "$price" 是一个表达式。

要了解详情,请参见表达式。

累加器可以计算多个输入文档的单个聚合值,例如总和、最大值或最小值。在实际实现中,累加器在执行分组操作时会维护所处理文档之间的省/市/自治区。

$group 阶段返回的输出文档数量等于组数。对于这些组中的每一组,累加器都会计算该组的聚合值。

您可以在执行分组操作的聚合管道阶段中使用累加器:

要了解更多信息,请参阅 累加器。

窗口函数返回一个基于窗口的值,窗口是相对于当前文档定义的文档范围。您可以使用 $setWindowFields 阶段的 partitionBy、sortBy 和 window 字段来定义窗口。

对于既可用作累加器又可用作窗口函数的操作符,其区别在于操作符聚合的内容以及返回的值的数量:

  • 作为累加器,该操作符对一组文档进行聚合,并为该组返回单个值。

  • 作为窗口函数,该操作符在文档窗口上进行聚合,并为每个文档返回一个值。

您只能在 $setWindowFields 阶段中使用窗口函数。$setWindowFields 也支持特定于窗口的操作符,例如 $rank 和 $shift。

要了解更多信息,请参阅 窗口函数。

本页上的示例使用来自 sample_mflix 数据集的数据。有关如何将此数据集加载到您的自管理 MongoDB 部署中的详细信息,请参阅 加载示例数据集。如果您对示例数据库进行了任何修改,您可能需要删除并重新创建数据库,才能运行此页面上的示例。

以下示例在所有三种上下文中使用 $sum。每个示例返回的结果都不同,这表明上下文如何决定操作符的行为。

以下示例使用 $sum 作为表达式,将每个文档中的两个字段相加。该管道为每个匹配的文档返回一个总数。

db.movies.aggregate( [ { $match: { title: { $in: [ "The Godfather", "Inception", "The Dark Knight" ] } } }, { $project: { _id: 0, title: 1, totalAwards: { $sum: [ "$awards.wins", "$awards.nominations" ] } } }, { $sort: { totalAwards: -1 } }] )

以下示例使用 $sum 作为累加器,对每个组中每个文档的字段进行汇总。管道为每个内容分级返回一个总计,而不是为每个文档返回一个总计。

db.movies.aggregate( [ { $match: { rated: { $in: [ "G", "PG", "PG-13", "R" ] }, "imdb.votes": { $type: "int" } } }, { $group: { _id: "$rated", totalVotes: { $sum: "$imdb.votes" } } }, { $sort: { _id: 1 } }] )

以下示例使用 $sum 作为窗口函数,对文档窗口中的一个字段进行汇总。该管道为每个文档返回一个运行总计,该总计取决于文档的窗口。

db.movies.aggregate( [ { $match: { genres: "Musical", year: { $in: [ 2009, 2010 ] }, "imdb.rating": { $type: "double" }, "imdb.votes": { $gt: 0 } } }, { $setWindowFields: { partitionBy: "$year", sortBy: { title: 1 }, output: { cumulativeVotesInYear: { $sum: "$imdb.votes", window: { documents: [ "unbounded", "current" ] } }, rankInYear: { $documentNumber: {} } } } }, { $project: { _id: 0, title: 1, year: 1, "imdb.votes": 1, cumulativeVotesInYear: 1, rankInYear: 1 } }, { $sort: { year: 1, title: 1 } }] )