文档菜单
文档首页
/
MongoDB 手册
/

聚合管道

在本页

  • 完整的聚合管道示例
  • 其他聚合管道阶段的详细信息
  • 运行聚合管道
  • 使用聚合管道更新文档
  • 其他注意事项
  • 了解更多

聚合管道由一个或多个阶段组成,这些阶段处理文档

  • 每个阶段对输入文档执行操作。例如,一个阶段可以过滤文档、分组文档和计算值。

  • 一个阶段输出的文档将被传递到下一个阶段。

  • 聚合管道可以为文档组返回结果。例如,返回总和、平均值、最大值和最小值。

如果您使用使用聚合管道更新中显示的阶段,则可以使用聚合管道更新文档。

注意

聚合管道通过db.collection.aggregate()方法运行,不会修改集合中的文档,除非管道包含$merge$out阶段。

当您在MongoDB Atlas UI上运行聚合管道时,您可以在每个阶段预览结果。

本节展示了使用以下披萨orders集合的聚合管道示例

db.orders.insertMany( [
{ _id: 0, name: "Pepperoni", size: "small", price: 19,
quantity: 10, date: ISODate( "2021-03-13T08:14:30Z" ) },
{ _id: 1, name: "Pepperoni", size: "medium", price: 20,
quantity: 20, date : ISODate( "2021-03-13T09:13:24Z" ) },
{ _id: 2, name: "Pepperoni", size: "large", price: 21,
quantity: 30, date : ISODate( "2021-03-17T09:22:12Z" ) },
{ _id: 3, name: "Cheese", size: "small", price: 12,
quantity: 15, date : ISODate( "2021-03-13T11:21:39.736Z" ) },
{ _id: 4, name: "Cheese", size: "medium", price: 13,
quantity:50, date : ISODate( "2022-01-12T21:23:13.331Z" ) },
{ _id: 5, name: "Cheese", size: "large", price: 14,
quantity: 10, date : ISODate( "2022-01-12T05:08:13Z" ) },
{ _id: 6, name: "Vegan", size: "small", price: 17,
quantity: 10, date : ISODate( "2021-01-13T05:08:13Z" ) },
{ _id: 7, name: "Vegan", size: "medium", price: 18,
quantity: 10, date : ISODate( "2021-01-13T05:10:13Z" ) }
] )

以下聚合管道示例包含两个 阶段,并返回按披萨名称分组的普通尺寸披萨的总订单数量

db.orders.aggregate( [
// Stage 1: Filter pizza order documents by pizza size
{
$match: { size: "medium" }
},
// Stage 2: Group remaining documents by pizza name and calculate total quantity
{
$group: { _id: "$name", totalQuantity: { $sum: "$quantity" } }
}
] )

$match 阶段

  • 过滤披萨订单文档,只保留尺寸为 medium 的披萨。

  • 将剩余文档传递给 $group 阶段。

$group 阶段

  • 按披萨 name 对剩余文档进行分组。

  • 使用 $sum 计算每个披萨 name 的总订单数量。总和存储在聚合管道返回的 totalQuantity 字段中。

示例输出

[
{ _id: 'Cheese', totalQuantity: 50 },
{ _id: 'Vegan', totalQuantity: 10 },
{ _id: 'Pepperoni', totalQuantity: 20 }
]

以下示例计算两个日期之间的总披萨订单价值和平均订单数量

db.orders.aggregate( [
// Stage 1: Filter pizza order documents by date range
{
$match:
{
"date": { $gte: new ISODate( "2020-01-30" ), $lt: new ISODate( "2022-01-30" ) }
}
},
// Stage 2: Group remaining documents by date and calculate results
{
$group:
{
_id: { $dateToString: { format: "%Y-%m-%d", date: "$date" } },
totalOrderValue: { $sum: { $multiply: [ "$price", "$quantity" ] } },
averageOrderQuantity: { $avg: "$quantity" }
}
},
// Stage 3: Sort documents by totalOrderValue in descending order
{
$sort: { totalOrderValue: -1 }
}
] )

$match 阶段

  • 使用 $gte$lt 过滤披萨订单文档。

  • 将剩余文档传递给 $group 阶段。

$group 阶段

  • 使用 $dateToString 按日期对文档进行分组。

  • 对于每个分组,计算

    • 使用 $sum$multiply 计算总订单价值。

    • 使用 $avg 计算平均订单数量。

  • 将分组文档传递给 $sort 阶段。

$sort 阶段

  • 按每个组的总订单价值降序排序文档(-1)。

  • 返回排序后的文档。

示例输出

[
{ _id: '2022-01-12', totalOrderValue: 790, averageOrderQuantity: 30 },
{ _id: '2021-03-13', totalOrderValue: 770, averageOrderQuantity: 15 },
{ _id: '2021-03-17', totalOrderValue: 630, averageOrderQuantity: 30 },
{ _id: '2021-01-13', totalOrderValue: 350, averageOrderQuantity: 10 }
]

提示

另请参阅

聚合管道由一个或多个处理文档的 阶段 组成。

  • 阶段不必为每个输入文档输出一个文档。例如,某些阶段可能产生新文档或过滤掉文档。

  • 以下阶段有例外,可以在管道中多次出现: $out$merge$geoNear

  • 要在一个阶段中计算平均值和其他计算,请使用指定 聚合表达式,这些表达式指定 聚合运算符。你将在下一节中了解更多关于聚合表达式的信息。

有关所有聚合阶段,请参阅 聚合阶段。

一些聚合管道阶段接受表达式。运算符根据输入表达式计算值。

在MongoDB查询语言中,您可以从以下组件构建表达式

组件
示例
常量
3
运算符
字段路径表达式
"$<path.to.field>"

例如,{ $add: [ 3, "$inventory.total" ] }是一个由$add运算符和两个输入表达式组成的表达式

该表达式返回将3添加到输入文档中路径inventory.total的值的结果。

字段路径表达式用于访问输入文档中的字段。要指定字段路径,使用美元符号$作为字段名或点字段路径(如果字段位于嵌套文档中)的前缀。例如,使用"$user"指定user字段的路由或使用"$user.name"指定到嵌套"user.name"字段的路由。

"$<field>"等同于"$$CURRENT.<field>",其中CURRENT是一个系统变量,默认为当前对象的根,除非在特定阶段中另有说明。

有关更多信息示例,请参阅字段路径

要运行聚合管道,请使用

要使用聚合管道更新文档,请使用

聚合管道对值类型和结果大小有限制。请参阅聚合管道限制。

聚合管道支持在分片集合上执行操作。请参阅聚合管道和分片集合。

从MongoDB 5.0开始,map-reduce 已弃用

  • 代替map-reduce,您应使用聚合管道。与map-reduce相比,聚合管道提供了更好的性能和易用性。

  • 您可以使用聚合管道阶段重写map-reduce操作,例如 $group$merge 等。

  • 对于需要自定义功能的map-reduce操作,您可以使用$accumulator$function聚合运算符。您可以使用这些运算符在JavaScript中定义自定义聚合表达式。

有关聚合管道替代map-reduce的示例,请参阅

要了解更多关于聚合管道的信息,请参阅

返回

聚合操作