写在前面:MongoDB的聚合管道是其最强大的功能之一,能够对数据进行复杂的处理、转换和统计分析。本篇将深入讲解聚合管道的各个阶段操作符,带您掌握MongoDB的数据分析能力。
文章目录
-
- 一、聚合管道基础
-
- [1.1 什么是聚合管道?](#1.1 什么是聚合管道?)
- [1.2 管道结构](#1.2 管道结构)
- 二、常用管道阶段
-
- [2.1 match - 数据过滤](#2.1 match - 数据过滤)
- [2.2 project - 字段投影](#2.2 project - 字段投影)
- [2.3 group - 分组统计](#2.3 group - 分组统计)
- [2.4 sort - 排序](#2.4 sort - 排序)
- [2.5 l i m i t 和 limit和 limit和skip - 分页](#2.5 l i m i t 和 limit和 limit和skip - 分页)
- [2.6 unwind - 数组展开](#2.6 unwind - 数组展开)
- 三、进阶管道操作
-
- [3.1 lookup - 联表查询](#3.1 lookup - 联表查询)
- [3.2 facet - 多维度聚合](#3.2 facet - 多维度聚合)
- [3.3 bucket - 分桶分组](#3.3 bucket - 分桶分组)
- 四、表达式与计算
-
- [4.1 算术表达式](#4.1 算术表达式)
- [4.2 字符串表达式](#4.2 字符串表达式)
- [4.3 日期表达式](#4.3 日期表达式)
- [4.4 条件表达式](#4.4 条件表达式)
- 五、实战案例
-
- [5.1 用户行为分析](#5.1 用户行为分析)
- [5.2 电商销售报表](#5.2 电商销售报表)
- 六、性能优化
-
- [6.1 管道优化原则](#6.1 管道优化原则)
- [6.2 查看执行计划](#6.2 查看执行计划)
- 七、总结
一、聚合管道基础
1.1 什么是聚合管道?
📊 聚合管道概念:
聚合管道(Aggregation Pipeline)是MongoDB用于数据处理和分析的框架,
类似于SQL中的GROUP BY、JOIN等功能,但更加强大和灵活。
特点:
✅ 多阶段数据处理
✅ 流水线式执行
✅ 支持复杂计算
✅ 高性能、易优化
1.2 管道结构
🔄 聚合管道执行流程:
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ $match │ ─▶│ $group │ ─▶│ $sort │ ─▶ │ $limit │
│ 过滤 │ │ 分组 │ │ 排序 │ │ 限制 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │ │ │
▼ ▼ ▼ ▼
文档1 统计结果 排序结果 最终结果
二、常用管道阶段
2.1 $match - 数据过滤
javascript
// 基本过滤
db.orders.aggregate([
{ $match: { status: "completed" } }
])
// 复杂条件
db.orders.aggregate([
{
$match: {
status: "completed",
total: { $gt: 1000 },
createdAt: { $gte: new Date("2024-01-01") }
}
}
])
// 建议:$match尽量放在管道最前面
// 这样可以提前过滤数据,减少后续处理量
2.2 $project - 字段投影
javascript
// 选择指定字段
db.orders.aggregate([
{
$project: {
orderId: 1,
customerName: "$customer.name",
total: 1,
_id: 0
}
}
])
// 计算新字段
db.products.aggregate([
{
$project: {
name: 1,
price: 1,
discount: 0.9,
finalPrice: { $multiply: ["$price", 0.9] }
}
}
])
// 条件字段
db.users.aggregate([
{
$project: {
name: 1,
age: 1,
status: {
$cond: {
if: { $gte: ["$age", 18] },
then: "adult",
else: "minor"
}
}
}
}
])
2.3 $group - 分组统计
javascript
// 按字段分组统计
db.orders.aggregate([
{
$group: {
_id: "$customer.city",
count: { $sum: 1 },
totalAmount: { $sum: "$total" },
avgAmount: { $avg: "$total" },
maxAmount: { $max: "$total" },
minAmount: { $min: "$total" }
}
}
])
// 多字段分组
db.orders.aggregate([
{
$group: {
_id: { city: "$customer.city", status: "$status" },
count: { $sum: 1 }
}
}
])
// 分组后排序
db.orders.aggregate([
{
$group: {
_id: "$customer.city",
totalAmount: { $sum: "$total" }
}
},
{ $sort: { totalAmount: -1 } }
])
2.4 $sort - 排序
javascript
// 按单个字段排序
db.orders.aggregate([
{ $sort: { total: -1 } }
])
// 多字段排序
db.orders.aggregate([
{ $sort: { status: 1, total: -1 } }
])
// 排序后限制
db.orders.aggregate([
{ $sort: { createdAt: -1 } },
{ $limit: 10 }
])
2.5 l i m i t 和 limit和 limit和skip - 分页
javascript
// 分页查询
db.orders.aggregate([
{ $sort: { createdAt: -1 } },
{ $skip: 0 },
{ $limit: 10 }
])
// 分页函数
function aggregatePage(collection, page, pageSize) {
return collection.aggregate([
{ $sort: { createdAt: -1 } },
{ $skip: (page - 1) * pageSize },
{ $limit: pageSize }
])
}
2.6 $unwind - 数组展开
javascript
// 插入测试数据
db.orders.insertMany([
{
orderId: "O001",
items: [
{ product: "iPhone", quantity: 1, price: 5999 },
{ product: "AirPods", quantity: 2, price: 998 }
]
},
{
orderId: "O002",
items: [
{ product: "MacBook", quantity: 1, price: 14999 }
]
}
])
// 展开items数组
db.orders.aggregate([
{ $unwind: "$items" }
])
// 结果:
// { orderId: "O001", items: { product: "iPhone", quantity: 1, price: 5999 } }
// { orderId: "O001", items: { product: "AirPods", quantity: 2, price: 998 } }
// { orderId: "O002", items: { product: "MacBook", quantity: 1, price: 14999 } }
// 保留数组索引
db.orders.aggregate([
{
$unwind: {
path: "$items",
includeArrayIndex: "arrayIndex"
}
}
])
三、进阶管道操作
3.1 $lookup - 联表查询
javascript
// 准备数据
db.products.insertMany([
{ _id: 1, name: "iPhone", categoryId: 101 },
{ _id: 2, name: "MacBook", categoryId: 102 }
])
db.categories.insertMany([
{ _id: 101, name: "手机" },
{ _id: 102, name: "电脑" }
])
// $lookup联表查询
db.products.aggregate([
{
$lookup: {
from: "categories",
localField: "categoryId",
foreignField: "_id",
as: "categoryInfo"
}
}
])
// 结果:
// { _id: 1, name: "iPhone", categoryId: 101, categoryInfo: [{ _id: 101, name: "手机" }] }
// 简化:使用pipeline(MongoDB 3.6+)
db.products.aggregate([
{
$lookup: {
from: "categories",
let: { categoryId: "$categoryId" },
pipeline: [
{ $match: { $expr: { $eq: ["$_id", "$$categoryId"] } } }
],
as: "categoryInfo"
}
}
])
3.2 $facet - 多维度聚合
javascript
// 一次性获取多个维度的统计
db.orders.aggregate([
{
$facet: {
// 按状态统计数量
byStatus: [
{ $group: { _id: "$status", count: { $sum: 1 } } }
],
// 按城市统计总额
byCity: [
{ $group: { _id: "$customer.city", total: { $sum: "$total" } } },
{ $sort: { total: -1 } },
{ $limit: 5 }
],
// 销售额趋势(按月)
monthlyTrend: [
{
$group: {
_id: { $month: "$createdAt" },
total: { $sum: "$total" }
}
},
{ $sort: { _id: 1 } }
],
// 热销商品TOP5
topProducts: [
{ $unwind: "$items" },
{ $group: { _id: "$items.product", totalQty: { $sum: "$items.quantity" } } },
{ $sort: { totalQty: -1 } },
{ $limit: 5 }
]
}
}
])
3.3 $bucket - 分桶分组
javascript
// 按价格区间分组
db.products.aggregate([
{
$bucket: {
groupBy: "$price",
boundaries: [0, 1000, 3000, 5000, 10000, Infinity],
default: "Other",
output: {
count: { $sum: 1 },
products: { $push: "$name" }
}
}
}
])
// 按年龄分段
db.users.aggregate([
{
$bucket: {
groupBy: "$age",
boundaries: [0, 18, 25, 35, 50, 60, 100],
default: "Unknown",
output: {
count: { $sum: 1 },
avgAge: { $avg: "$age" }
}
}
}
])
四、表达式与计算
4.1 算术表达式
javascript
// $add、$subtract、$multiply、$divide、$mod
db.products.aggregate([
{
$project: {
name: 1,
price: 1,
cost: 1,
profit: { $subtract: ["$price", "$cost"] },
tax: { $multiply: ["$price", 0.1] },
finalPrice: { $add: ["$price", { $multiply: ["$price", 0.1] }] }
}
}
])
// 四舍五入
db.products.aggregate([
{
$project: {
name: 1,
price: 1,
roundedPrice: { $round: ["$price", 0] }
}
}
])
4.2 字符串表达式
javascript
// $concat、$toUpper、$toLower、$substr
db.users.aggregate([
{
$project: {
fullName: { $concat: ["$firstName", " ", "$lastName"] },
emailUpper: { $toUpper: "$email" },
username: { $toLower: "$username" }
}
}
])
// 字符串截取
db.products.aggregate([
{
$project: {
name: 1,
shortName: { $substr: ["$name", 0, 10] }
}
}
])
4.3 日期表达式
javascript
// $year、$month、$dayOfMonth、$hour、$minute
db.orders.aggregate([
{
$project: {
orderId: 1,
createdAt: 1,
year: { $year: "$createdAt" },
month: { $month: "$createdAt" },
day: { $dayOfMonth: "$createdAt" },
hour: { $hour: "$createdAt" }
}
}
])
// 日期格式化(MongoDB 5.0+)
db.orders.aggregate([
{
$project: {
orderId: 1,
dateStr: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } }
}
}
])
4.4 条件表达式
javascript
// $cond(三元运算符)
db.products.aggregate([
{
$project: {
name: 1,
price: 1,
level: {
$cond: {
if: { $gte: ["$price", 5000] },
then: "高端",
else: {
$cond: {
if: { $gte: ["$price", 2000] },
then: "中端",
else: "入门"
}
}
}
}
}
}
])
// $switch(多条件)
db.users.aggregate([
{
$project: {
name: 1,
age: 1,
category: {
$switch: {
branches: [
{ case: { $lt: ["$age", 18] }, then: "未成年" },
{ case: { $lt: ["$age", 30] }, then: "青年" },
{ case: { $lt: ["$age", 50] }, then: "中年" }
],
default: "老年"
}
}
}
}
])
五、实战案例
5.1 用户行为分析
javascript
// 插入用户行为日志
db.user_actions.insertMany([
{ userId: 1, action: "view", product: "iPhone", timestamp: new Date("2024-01-15T10:00:00Z") },
{ userId: 1, action: "cart", product: "iPhone", timestamp: new Date("2024-01-15T10:05:00Z") },
{ userId: 1, action: "buy", product: "iPhone", timestamp: new Date("2024-01-15T10:10:00Z") },
{ userId: 2, action: "view", product: "MacBook", timestamp: new Date("2024-01-15T11:00:00Z") },
{ userId: 2, action: "view", product: "iPad", timestamp: new Date("2024-01-15T11:05:00Z") }
])
// 1. 统计每日活跃用户数
db.user_actions.aggregate([
{
$group: {
_id: { $dateToString: { format: "%Y-%m-%d", date: "$timestamp" } },
activeUsers: { $addToSet: "$userId" }
}
},
{
$project: {
date: "$_id",
activeUserCount: { $size: "$activeUsers" },
_id: 0
}
}
])
// 2. 统计用户转化率(浏览 → 加购 → 购买)
db.user_actions.aggregate([
{ $group: { _id: "$userId", actions: { $push: "$action" } } },
{
$project: {
userId: "$_id",
viewed: { $in: ["view", "$actions"] },
carted: { $in: ["cart", "$actions"] },
bought: { $in: ["buy", "$actions"] }
}
}
])
5.2 电商销售报表
javascript
// 销售数据统计
db.orders.aggregate([
// 1. 过滤已完成订单
{ $match: { status: "completed" } },
// 2. 展开订单明细
{ $unwind: "$items" },
// 3. 按商品分组统计
{
$group: {
_id: "$items.product",
totalQuantity: { $sum: "$items.quantity" },
totalRevenue: { $sum: { $multiply: ["$items.price", "$items.quantity"] } }
}
},
// 4. 按销售额排序
{ $sort: { totalRevenue: -1 } },
// 5. 取TOP10
{ $limit: 10 },
// 6. 格式化输出
{
$project: {
product: "$_id",
totalQuantity: 1,
totalRevenue: 1,
_id: 0
}
}
])
六、性能优化
6.1 管道优化原则
💡 聚合管道优化技巧:
1. $match放最前面
- 提前过滤数据,减少后续处理量
2. $sort尽量靠前
- 排序后limit更高效
3. $limit紧随$sort
- 减少中间结果数量
4. 避免$project不必要的字段
- 减少数据传输
5. 使用$match中的索引
- 查看explain计划
6.2 查看执行计划
javascript
// 查看聚合管道执行计划
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$customer.city", total: { $sum: "$total" } } }
], { explain: true })
七、总结
📊 本篇总结:
✅ 掌握内容:
- 聚合管道基础概念
- 常用管道阶段:$match、$project、$group、$sort、$limit、$skip、$unwind
- 进阶操作:$lookup联表、$facet多维度、$bucket分桶
- 表达式:算术、字符串、日期、条件
- 实战案例:用户行为分析、销售报表
- 性能优化技巧
作者 :刘~浪地球
更新时间 :2026-05-09
本文声明:原创不易,转载需授权!