MongoDB 聚合(Aggregation)
MongoDB 聚合(Aggregation) 通过 aggregate() 方法对文档进行复杂的数据处理,如分组、过滤、排序、计算统计值等,类似 SQL 的 GROUP BY 和 HAVING 语句。
1. 聚合管道(Aggregation Pipeline)
MongoDB 采用 Pipeline(管道)机制,多个操作可以依次处理数据,每个操作的输出作为下一个操作的输入。
db.collection.aggregate([
{ stage1 },
{ stage2 },
{ stage3 }
])
- 每个
stage(阶段)是一个数据处理步骤,MongoDB 依次执行。
2. 主要聚合操作符
| 操作符 | 作用 |
|---|---|
$match | 过滤数据(类似 SQL WHERE) |
$group | 分组(类似 SQL GROUP BY) |
$sort | 排序(类似 SQL ORDER BY) |
$project | 指定返回字段(类似 SQL SELECT) |
$limit | 限制返回数量(类似 SQL LIMIT) |
$skip | 跳过指定数量的文档(类似 SQL OFFSET) |
$count | 统计总数 |
$unwind | 拆分数组 |
$lookup | 关联查询(类似 SQL JOIN) |
$addFields | 添加计算字段 |
$set | 修改或新增字段(MongoDB 4.2+) |
$unset | 移除字段 |
$merge | 结果存入新集合 |
3. 过滤数据($match)
$match 作用类似 WHERE,用于筛选符合条件的数据,减少后续处理的数据量。
示例
查询 status 为 "active" 且 price > 100 的商品:
db.products.aggregate([
{ $match: { status: "active", price: { $gt: 100 } } }
])
等价于 SQL:
SELECT * FROM products WHERE status = 'active' AND price > 100;
4. 分组统计($group)
$group 类似 SQL GROUP BY,可以按照某字段分组,并计算统计值。
示例
按 category 分组,统计每个类别的商品数量:
db.products.aggregate([
{ $group: { _id: "$category", count: { $sum: 1 } } }
])
_id: "$category"→ 按category分组。count: { $sum: 1 }→ 统计该分组内的文档数。
等价于 SQL:
SELECT category, COUNT(*) FROM products GROUP BY category;
其他常用统计运算
| 操作符 | 作用 |
|---|---|
$sum | 计算总和 |
$avg | 计算平均值 |
$max | 计算最大值 |
$min | 计算最小值 |
$first | 取分组中的第一个值 |
$last | 取分组中的最后一个值 |
5. 指定返回字段($project)
$project 用于指定需要返回的字段,类似 SQL SELECT。
示例
仅返回 name 和 price 字段:
db.products.aggregate([
{ $project: { name: 1, price: 1, _id: 0 } }
])
1表示显示该字段。_id: 0表示隐藏_id字段(MongoDB 默认会返回_id)。
等价于 SQL:
SELECT name, price FROM products;
计算新字段
使用 $project 计算新字段:
db.products.aggregate([
{ $project: { name: 1, priceWithTax: { $multiply: ["$price", 1.1] } } }
])
priceWithTax是计算后的新字段(商品价格 × 1.1)。
6. 排序($sort)
$sort 类似 SQL ORDER BY,用于对结果排序。
示例
按 price 降序排序:
db.products.aggregate([
{ $sort: { price: -1 } }
])
1表示升序(ASC)。-1表示降序(DESC)。
等价于 SQL:
SELECT * FROM products ORDER BY price DESC;
7. 限制 & 跳过($limit & $skip)
$limit→ 限制返回数量。$skip→ 跳过指定数量的文档(通常用于分页)。
示例
获取第 2 页,每页 5 条数据:
db.products.aggregate([
{ $skip: 5 }, // 跳过前 5 条
{ $limit: 5 } // 获取 5 条
])
等价于 SQL:
SELECT * FROM products LIMIT 5 OFFSET 5;
8. 拆分数组($unwind)
$unwind 将数组字段拆分成多行数据。
示例
假设 orders 集合的 items 字段是数组:
{ _id: 1, customer: "Alice", items: ["Apple", "Banana"] }
{ _id: 2, customer: "Bob", items: ["Orange"] }
使用 $unwind 拆分:
db.orders.aggregate([
{ $unwind: "$items" }
])
结果:
{ _id: 1, customer: "Alice", items: "Apple" }
{ _id: 1, customer: "Alice", items: "Banana" }
{ _id: 2, customer: "Bob", items: "Orange" }
等价于 SQL 一对多拆分。
9. 关联查询($lookup,类似 SQL JOIN)
MongoDB 没有外键,但可以使用 $lookup 进行类似 SQL JOIN 的查询。
示例
在 orders 集合中查询 users 表的用户信息:
db.orders.aggregate([
{
$lookup: {
from: "users", // 关联集合
localField: "userId", // 当前集合的字段
foreignField: "_id", // 目标集合的字段
as: "userInfo" // 关联数据的字段名
}
}
])
等价于 SQL:
SELECT orders.*, users.*
FROM orders
JOIN users ON orders.userId = users._id;
10. 统计文档数($count)
统计 status="active" 的商品数:
db.products.aggregate([
{ $match: { status: "active" } },
{ $count: "totalActiveProducts" }
])
总结
| 操作 | MongoDB 聚合 | SQL 对应 |
|---|---|---|
| 过滤 | $match | WHERE |
| 分组 | $group | GROUP BY |
| 计算 | $sum, $avg, $max | SUM(), AVG(), MAX() |
| 排序 | $sort | ORDER BY |
| 限制返回 | $limit | LIMIT |
| 跳过 | $skip | OFFSET |
| 选择字段 | $project | SELECT |
| 拆分数组 | $unwind | 无直接对应 |
| 关联查询 | $lookup | JOIN |
MongoDB 聚合 是强大的数据处理工具,可以实现复杂的数据分析!更多详细内容请关注其他相关文章!