<返回目录     Powered by claud/xia兄

第9课: 聚合框架

什么是聚合框架?

聚合框架是MongoDB的数据处理管道,用于对文档进行复杂的数据分析和转换。类似于SQL的GROUP BY、JOIN等操作。

聚合管道

// 基本语法
db.collection.aggregate([
    { stage1 },
    { stage2 },
    { stage3 }
])

// 数据按顺序通过每个阶段处理

$match - 过滤文档

// 类似于find()的查询条件
db.orders.aggregate([
    {
        $match: {
            status: "completed",
            total: { $gte: 100 }
        }
    }
])

// 应该尽早使用$match减少后续处理的数据量

$group - 分组聚合

// 按城市分组统计用户数量
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" }

$project - 投影字段

// 选择和重命名字段
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" }
        }
    }
])

$sort - 排序

// 按字段排序
db.products.aggregate([
    { $match: { category: "电子产品" } },
    { $sort: { price: -1 } }  // 价格降序
])

// 多字段排序
db.users.aggregate([
    { $sort: { city: 1, age: -1 } }
])

$limit 和 $skip

// 分页
db.products.aggregate([
    { $match: { stock: { $gt: 0 } } },
    { $sort: { sales: -1 } },
    { $skip: 20 },
    { $limit: 10 }
])

$lookup - 关联查询

// 类似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: "..." }
    ]
}

$unwind - 展开数组

// 将数组字段展开为多个文档
db.users.aggregate([
    { $unwind: "$hobbies" }
])

// 输入
{ name: "张三", hobbies: ["读书", "旅游"] }

// 输出
{ name: "张三", hobbies: "读书" }
{ name: "张三", hobbies: "旅游" }

$addFields - 添加字段

// 添加计算字段
db.products.aggregate([
    {
        $addFields: {
            discountPrice: { $multiply: ["$price", 0.8] },
            inStock: { $gt: ["$stock", 0] }
        }
    }
])

$count - 计数

// 统计文档数量
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]
                }
            }
        }
    }
])
性能优化建议:
练习题:
  1. 统计每个城市的用户数量和平均年龄
  2. 查询销售额前10的商品
  3. 统计每月的订单数量和总金额
  4. 使用$lookup关联订单和用户信息
  5. 展开用户的爱好数组,统计每个爱好的人数
  6. 计算每个分类中价格最高和最低的商品