聚合管道 aggregate
MongoDB 的 aggregate()方法是其聚合框架的核心,用于对数据进行复杂的计算、转换和分析。
它通过一个由多个阶段(Stage) 组成的管道(Pipeline) 来处理数据,每个阶段对输入文档执行特定操作,并将结果传递给下一阶段。
常用聚合阶段 Stage
$match 过滤
在管道初期使用 $match
可以大幅减少后续阶段需要处理的文档数量,提升聚合效率。
$group 分组
按指定的标识符 _id
表达式对文档进行分组,并对每个分组应用聚合表达式(如 $sum
, $avg
)进行计算。这是进行统计汇总的核心阶段。_id: null
可将所有文档分到同一组进行整体计算。
{
$group: {
_id: '$customer_id',
first_purchase_date: { $first: '$orderdate' },
total_value: { $sum: '$value' },
total_orders: { $sum: 1 },
orders: {
$push: {
orderdate: '$orderdate',
value: '$value',
},
},
},
}
$project 投影
重塑文档结构,类似于 SQL 中的 SELECT。作用如下:
- 保留、排除特定字段(设置 1或 0)。
- 重命名字段。
- 插入新计算字段(如使用 $multiply, $divide等运算符)。
默认情况下_id
字段会被包含,可以显式设置_id: 0
来排除它
删除文档中的指定字段
$sort 排序
根据指定字段对文档进行排序,可选升序(1)或降序(-1)。
$limit 限制
限制返回的文档数量,用于分页或获取前 N 个结果。
$skip 跳过
跳过指定数量的文档,用于分页。
$unwind 展开
将数组字段拆分成多个文档,每个文档包含数组中的一个元素。
可以使用 preserveNullAndEmptyArrays: true
选项来防止在数组为空、不存在或为 null 时丢弃该文档
$lookup 关联
从另一个集合中查询与输入文档相关的文档,并将匹配的结果作为一个新数组字段添加到输入文档中
$densify 填充缺失
为指定字段的缺失值自动创建新的文档
{
$densify: {
field: <fieldName>,
partitionByFields: [ <field1>, <field2>, ... <fieldn> ],
range: {
step: <number>,
unit: <timeUnit>, // 仅当字段为日期类型时需要
bounds: < "full" | "partition" | [ <lowerBound>, <upperBound> ] >
}
}
}
$setWindowFields 窗口函数
为每个文档计算窗口函数值,如滚动平均值、滚动总和等。
{
$setWindowFields: {
partitionBy: <expression>, // 可选:指定分组字段
sortBy: <sortSpec>, // 必需:指定窗口内数据的排序方式
output: { // 必需:指定要添加的新字段及其计算方式
<outputField>: {
<windowOperator>: <expression>,
window: {
documents | range: [ <lowerBound>, <upperBound> ]
}
},
... // 可以添加多个输出字段
}
}
}
注意事项:
- 字段类型限制:如果集合中有文档的
field
字段是日期类型,则必须指定unit
;如果是数值类型,则不能指定unit
,否则会报错。 - 输出顺序:
$densify
不保证输出文档的顺序。如果需要特定的顺序(例如按时间或数值排序),应在$densify
阶段之后使用$sort
阶段。 - 新文档的字段:由
$densify
创建的新文档通常只包含field
字段和partitionByFields
中指定的字段(如果使用了分区)。原文档中的其他字段在这些新创建的文档中不会出现。
聚合表达式
统计类
$sum
:求和。$sum: 1
表示计数。$avg
:均值$min / $max
获取最小/最大值$first/ $last
:获取第一个/最后一个文档的指定字段
数组操作类
$push
:将值添加到结果数组中(允许重复)$addToSet
:将值添加到结果数组中(确保唯一,不重复)
算数操作符
常用于 $project
阶段进行字段间的计算
$multiply
:乘法$divide
:除法
优化建议
- 管道顺序至关重要:阶段的顺序会直接影响聚合结果和性能。通常应优先使用
$match
和$project
阶段来尽可能早地过滤和减少文档的大小与数量。 - 索引的使用:在
$match
和$sort
阶段涉及的字段上创建索引可以显著提高聚合查询的速度。 - 内存限制与磁盘使用:
- 每个聚合管道阶段最多只能使用 100MB 内存。如果处理大量数据时可能超出此限制,可以通过设置
allowDiskUse: true
选项允许 MongoDB 将临时数据写入磁盘,但这会降低性能。 - 聚合结果返回的单个文档不能超过 16MB 的 BSON 文档大小限制。对于大型结果集,应使用返回游标(cursor)的方式。
- 每个聚合管道阶段最多只能使用 100MB 内存。如果处理大量数据时可能超出此限制,可以通过设置