聚合框架是MongoDB的数据处理管道,用于对文档进行复杂的数据分析和转换。类似于SQL的GROUP BY、JOIN等操作。
// 基本语法
db.collection.aggregate([
{ stage1 },
{ stage2 },
{ stage3 }
])
// 数据按顺序通过每个阶段处理
// 类似于find()的查询条件
db.orders.aggregate([
{
$match: {
status: "completed",
total: { $gte: 100 }
}
}
])
// 应该尽早使用$match减少后续处理的数据量
// 按城市分组统计用户数量
db.users.aggregate([
{
$group: {
_id: "$city", // 分组字段
count: { $sum: 1 }, // 计数
avgAge: { $avg: "$age" } // 平均年龄
}
}
])
// 结果示例
[
{ _id: "北京", count: 150, avgAge: 28.5 },
{ _id: "上海", count: 120, avgAge: 30.2 }
]
| 操作符 | 说明 | 示例 |
|---|---|---|
| $sum | 求和 | { $sum: "$amount" } |
| $avg | 平均值 | { $avg: "$price" } |
| $min | 最小值 | { $min: "$age" } |
| $max | 最大值 | { $max: "$score" } |
| $first | 第一个值 | { $first: "$name" } |
| $last | 最后一个值 | { $last: "$date" } |
| $push | 添加到数组 | { $push: "$item" } |
| $addToSet | 添加到数组(去重) | { $addToSet: "$tag" } |
// 选择和重命名字段
db.users.aggregate([
{
$project: {
_id: 0,
userName: "$name", // 重命名
age: 1, // 包含
email: 1,
isAdult: { $gte: ["$age", 18] } // 计算字段
}
}
])
// 字符串操作
db.users.aggregate([
{
$project: {
fullName: { $concat: ["$firstName", " ", "$lastName"] },
upperName: { $toUpper: "$name" },
year: { $year: "$birthDate" }
}
}
])
// 按字段排序
db.products.aggregate([
{ $match: { category: "电子产品" } },
{ $sort: { price: -1 } } // 价格降序
])
// 多字段排序
db.users.aggregate([
{ $sort: { city: 1, age: -1 } }
])
// 分页
db.products.aggregate([
{ $match: { stock: { $gt: 0 } } },
{ $sort: { sales: -1 } },
{ $skip: 20 },
{ $limit: 10 }
])
// 类似SQL的LEFT JOIN
db.orders.aggregate([
{
$lookup: {
from: "users", // 关联的集合
localField: "userId", // 本集合的字段
foreignField: "_id", // 关联集合的字段
as: "userInfo" // 输出字段名
}
}
])
// 结果包含关联的用户信息
{
_id: ObjectId("..."),
userId: "user123",
total: 299,
userInfo: [
{ _id: "user123", name: "张三", email: "..." }
]
}
// 将数组字段展开为多个文档
db.users.aggregate([
{ $unwind: "$hobbies" }
])
// 输入
{ name: "张三", hobbies: ["读书", "旅游"] }
// 输出
{ name: "张三", hobbies: "读书" }
{ name: "张三", hobbies: "旅游" }
// 添加计算字段
db.products.aggregate([
{
$addFields: {
discountPrice: { $multiply: ["$price", 0.8] },
inStock: { $gt: ["$stock", 0] }
}
}
])
// 统计文档数量
db.users.aggregate([
{ $match: { age: { $gte: 18 } } },
{ $count: "adultCount" }
])
// 结果
{ adultCount: 1250 }
// 电商系统:统计每个分类的销售情况
db.orders.aggregate([
// 1. 只统计已完成的订单
{ $match: { status: "completed" } },
// 2. 展开订单项
{ $unwind: "$items" },
// 3. 关联商品信息
{
$lookup: {
from: "products",
localField: "items.productId",
foreignField: "_id",
as: "product"
}
},
// 4. 展开商品信息
{ $unwind: "$product" },
// 5. 按分类分组统计
{
$group: {
_id: "$product.category",
totalSales: { $sum: "$items.quantity" },
totalRevenue: {
$sum: { $multiply: ["$items.quantity", "$items.price"] }
},
avgPrice: { $avg: "$items.price" },
orderCount: { $sum: 1 }
}
},
// 6. 按销售额降序排序
{ $sort: { totalRevenue: -1 } },
// 7. 添加排名
{
$group: {
_id: null,
categories: { $push: "$$ROOT" }
}
},
{
$unwind: { path: "$categories", includeArrayIndex: "rank" }
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$categories",
{ rank: { $add: ["$rank", 1] } }
]
}
}
}
])
// 按月统计订单
db.orders.aggregate([
{
$group: {
_id: {
year: { $year: "$createdAt" },
month: { $month: "$createdAt" }
},
count: { $sum: 1 },
total: { $sum: "$amount" }
}
},
{ $sort: { "_id.year": -1, "_id.month": -1 } }
])
// 使用$cond进行条件统计
db.users.aggregate([
{
$group: {
_id: "$city",
total: { $sum: 1 },
adults: {
$sum: {
$cond: [{ $gte: ["$age", 18] }, 1, 0]
}
},
minors: {
$sum: {
$cond: [{ $lt: ["$age", 18] }, 1, 0]
}
}
}
}
])