MongoDB 不仅仅是简单的文档存储——它的聚合管道相当于关系数据库的 GROUP BY + JOIN + 窗口函数的合体。

管道核心阶段

阶段 作用 类比 SQL
$match 过滤文档 WHERE
$group 分组聚合 GROUP BY
$sort 排序 ORDER BY
$project 字段筛选计算 SELECT
$limit/$skip 限制/跳过 LIMIT/OFFSET
$lookup 联表查询 LEFT JOIN
$unwind 数组展开为多行 无直接类比
$addFields 新增计算字段 计算列

管道顺序很重要:$match 尽量放前面(尽早减少数据量)、$lookup 放 $match 之后、$project 放最后做数据整形。

我的踩坑记:聚合管道撑爆内存

去年有个报表需求——统计过去一年每天的销售金额。我第一版管道 $match 全年 -> $group by day,看起来没毛病。结果线上跑了 40 秒后直接返回错误:Exceeded memory limit。

根因是 $group 阶段在内存里维护了 365 个桶,每个桶还带着原始文档,300 万订单数据直接把 100MB 的默认内存限制撑爆。加 allowDiskUse: true 后能跑了但慢得离谱。最终方案:$match 后先 $project 只留 3 个字段,再 $group,配合 ${dateToString}` 把日期归一化——优化后从 40 秒降到 1.2 秒。聚合管道的黄金法则:每个阶段只往下传必需的字段,数据量越往后越小。

$lookup:MongoDB 的 JOIN

$lookup 支持管道子表达式——可以在 lookup 内部先过滤再关联,比 SQL 的 JOIN + WHERE 更灵活。但大表关联时性能较差,频繁关联场景考虑内嵌文档或预聚合。

$unwind:拆解数组

文档中的数组字段用 $unwind 展开——每展开一个数组元素就产生一行新文档。配合 $group 可以做按数组元素的统计。例如订单中的商品列表展开后统计每个商品的销量。

窗口函数:$setWindowFields

MongoDB 5.0+ 支持窗口函数,可以做移动平均、排名、累计求和等操作。不需要再把数据拉到应用层计算——直接在数据库里一步完成。

性能优化

$match 和 $sort 可以利用索引,其他阶段不走索引。对于超大集合,使用 allowDiskUse 允许管道使用磁盘临时存储(超过 100MB 内存限制时必需)。

总结

聚合管道是 MongoDB 最被低估的能力。一条管道替代了 SQL 多条语句 + 应用层处理。理解 $match/$group/$lookup/$unwind 这四个核心阶段,就能用 MongoDB 做实时数据分析。