MongoDB - 聚合
MongoDB - 聚合管道
Section titled “MongoDB - 聚合管道”聚合管道(Aggregation Pipeline)是 MongoDB 中用于数据处理的强大框架。它将数据处理建模为一个多阶段管道,文档进入后,通过一系列转换阶段,然后以聚合结果的形式输出。这是现代且高度推荐的替代方案,取代了现在已弃用的 MapReduce 框架。
The aggregate() 方法与管道概念
Section titled “The aggregate() 方法与管道概念”aggregate() 方法将一个阶段数组作为其参数。每个阶段对文档执行特定操作。一个阶段的输出成为下一个阶段的输入。
db.collection.aggregate([ { <stage1> }, { <stage2> }, // ... 更多阶段]);小型项目:分析电子商务订单
Section titled “小型项目:分析电子商务订单”让我们使用一个更真实的 orders 集合。每个文档代表一个客户订单。
/* 订单文档示例 */{ "customerId": "CUST123", "orderDate": ISODate("2024-07-15T10:00:00Z"), "status": "completed", "items": [ { "productId": "PROD01", "quantity": 2, "price": 25.00 }, { "productId": "PROD05", "quantity": 1, "price": 100.50 } ], "totalAmount": 150.50},{ "customerId": "CUST456", "orderDate": ISODate("2024-07-16T14:30:00Z"), "status": "completed", "items": [ { "productId": "PROD01", "quantity": 5, "price": 25.00 } ], "totalAmount": 125.00},{ "customerId": "CUST123", "orderDate": ISODate("2024-06-20T11:00:00Z"), "status": "shipped", "totalAmount": 75.00}目标: 查找 2024 年 7 月所有“已完成”订单的总收入,并按客户分组。
db.orders.aggregate([ // 阶段 1:首先过滤相关文档以提高性能 { $match: { status: "completed", orderDate: { $gte: ISODate("2024-07-01T00:00:00Z"), $lt: ISODate("2024-08-01T00:00:00Z") } } }, // 阶段 2:按 customerId 分组并计算总计 { $group: { _id: "$customerId", totalRevenue: { $sum: "$totalAmount" }, orderCount: { $sum: 1 } } }, // 阶段 3:按最高收入排序 { $sort: { totalRevenue: -1 } }]);这个管道展示了一个最佳实践:尽早使用 $match 进行过滤,以减少后续更耗性能的阶段(如 $group 和 $sort)处理的文档数量。
常用聚合阶段
Section titled “常用聚合阶段”| Stage | Description |
|---|---|
| $match | 过滤文档流,只允许匹配的文档进入下一个管道阶段。应尽可能早地放置。 |
| $group | 根据指定的标识符表达式对输入文档进行分组,并对每个组应用累加器表达式。 |
| $project | 重塑流中的每个文档,例如添加新字段或删除现有字段。也用于包含/排除字段。 |
| $sort | 根据指定的排序键重新排序文档流。 |
| $limit | 将前 n 个文档(n 是指定限制)未经修改地传递到管道中。 |
| $unwind | 从输入文档中解构一个数组字段,为每个元素输出一个文档。 |
| $lookup | 对同一数据库中的另一个集合执行左外连接,以将“连接”集合中的文档过滤进来进行处理。 |
| $set (或 $addFields) | 向文档添加新字段。$set 是 $addFields 的别名。 |
关键累加器表达式(用于 $group)
Section titled “关键累加器表达式(用于 $group)”| Expression | Description |
|---|---|
| $sum | 返回数值的总和。可以与值 1 一起使用以计数文档。 |
| $avg | 计算所有给定数值的平均值。 |
| $min / $max | 获取对应值的最小值或最大值。 |
| $push | 返回将表达式应用于组中文档所产生的所有值的数组。 |
| $addToSet | 返回将表达式应用于组中文档所产生的唯一值的数组。 |
| $first / $last | 返回将表达式应用于组中第一个/最后一个文档所产生的值。 |
聚合的最佳实践
Section titled “聚合的最佳实践”- 尽早频繁过滤:在管道的开始处使用
$match。 - 使用索引:如果您的管道以
$match或$sort开始,请确保这些字段已建立索引,以加快初始阶段的速度。 - 只投影所需字段:尽早使用
$project或$unset移除不必要的字段,减少阶段之间传递的文档大小。 - 理解内存限制:复杂的聚合管道会消耗大量内存。对于非常大的数据集,启用
allowDiskUse: true选项,允许 MongoDB 将数据写入磁盘上的临时文件。