MongoDB聚合管道进阶:数据处理与统计分析

写在前面: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
本文声明:原创不易,转载需授权!

相关推荐
瀚高PG实验室1 小时前
debezium在LANG=zh_CN.UTF-8下,无法解析timestamp类型的列值为BC的字段
服务器·数据库·postgresql·瀚高数据库
刘~浪地球1 小时前
MongoDB索引优化实战:让查询飞起来
数据库·mongodb
AstartesEternal1 小时前
REDIS下载及安装教程
数据库·redis·缓存
Allen_LVyingbo1 小时前
面向医疗群体智能的协同诊疗与群体决策支持系统(上)
数据结构·数据库·人工智能·git·python·动态规划
东南门吹雪2 小时前
Spring事务传播机制深度解析
java·数据库·spring
不甘先生2 小时前
PostgreSQL 中的 JSONB 详解:从入门到实战
数据库·postgresql
Irene19912 小时前
PL/SQL:异常处理补充
数据库·sql
dishugj2 小时前
SAP HANA数据库文件目录说明
服务器·数据库·oracle
l1t2 小时前
DeepSeek总结的使用 eBPF 和硬件断点跟踪 PostgreSQL
数据库·驱动开发·postgresql