MongoDB入门学习教程,从入门到精通,MongoDB聚合框架(7)

MongoDB聚合框架

7.1 聚合框架概述

7.1.1 什么是聚合框架

聚合框架是MongoDB中用于数据聚合、转换和分析的强大工具,类似于SQL中的GROUP BYJOIN、聚合函数等功能的组合。它基于管道(Pipeline) 概念,通过一系列阶段(Stage) 对文档进行处理,最终返回计算结果。

7.1.2 核心优势

  • 声明式语法,易于理解
  • 支持多阶段组合,灵活处理复杂数据
  • 内部优化,性能高效
  • 可直接将结果写入集合,便于后续使用

7.2 管道、阶段和可调参数

7.2.1 管道

管道是一系列阶段的序列,每个阶段对输入的文档执行某种转换,输出结果作为下一阶段的输入。数据在管道中依次流转,最终返回处理后的结果。

javascript 复制代码
db.collection.aggregate([
  { $match: { status: "A" } },    // 阶段1:过滤
  { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }, // 阶段2:分组聚合
  { $sort: { total: -1 } }         // 阶段3:排序
]);

7.2.2 阶段

每个阶段完成特定的数据处理任务。常见阶段包括:

  • $match:过滤文档
  • $project:重塑文档结构
  • $group:分组聚合
  • $sort:排序
  • $limit / $skip:分页
  • $unwind:拆分数组
  • $lookup:关联查询
  • $addFields:添加新字段
  • $out / $merge:输出结果

7.2.3 可调参数

MongoDB允许对聚合操作进行性能调优:

  • allowDiskUse:允许使用磁盘存储临时数据,避免内存限制(默认内存限制为100MB)
  • explain:查看聚合管道的执行计划,分析性能瓶颈
  • hint:强制使用指定索引
javascript 复制代码
db.orders.aggregate(pipeline, { allowDiskUse: true });

7.3 阶段入门:常见操作

7.3.1 $match:过滤数据

类似于SQL中的WHERE子句,尽早使用可以缩小数据量,提升性能。

javascript 复制代码
{ $match: { status: "shipped", amount: { $gt: 100 } } }

7.3.2 $sort:排序

在内存中进行排序,如果数据量大且启用了allowDiskUse,可以使用磁盘排序。

javascript 复制代码
{ $sort: { createdAt: -1, amount: 1 } }

7.3.3 $limit$skip:分页

javascript 复制代码
{ $skip: 10 },
{ $limit: 10 }

7.3.4 $lookup:关联查询

实现类似SQL的LEFT OUTER JOIN功能。

javascript 复制代码
{
  $lookup: {
    from: "inventory",
    localField: "productId",
    foreignField: "_id",
    as: "productDetails"
  }
}

7.3.5 $addFields:添加字段

为文档添加新字段,不改变原有文档结构。

javascript 复制代码
{ $addFields: { totalPrice: { $multiply: ["$price", "$quantity"] } } }

7.4 表达式

7.4.1 概述

表达式用于在阶段内部执行计算、比较、逻辑判断等操作。它们可以用于字段投影、条件判断、数学运算等场景。

7.4.2 表达式类型

  • 布尔表达式$and, $or, $not
  • 比较表达式$eq, $gt, $lt, $gte, $lte, $ne
  • 条件表达式$cond, $ifNull, $switch
  • 算术表达式$add, $subtract, $multiply, $divide, $mod
  • 字符串表达式$concat, $substr, $toUpper, $toLower
  • 日期表达式$year, $month, $dayOfMonth, $dateToString
  • 数组表达式$size, $slice, $concatArrays, $filter

7.4.3 示例

javascript 复制代码
{
  $project: {
    fullName: { $concat: ["$firstName", " ", "$lastName"] },
    isAdult: { $gte: ["$age", 18] },
    birthYear: { $year: "$birthDate" }
  }
}

7.5 $project

7.5.1 作用

  • 选择需要输出的字段(类似SQL的SELECT
  • 重命名字段
  • 计算新字段
  • 排除字段

7.5.2 基本语法

javascript 复制代码
{ $project: { field1: 1, field2: 1, newField: { $add: ["$a", "$b"] }, _id: 0 } }

7.5.3 常用场景

javascript 复制代码
// 选择字段
{ $project: { name: 1, email: 1 } }

// 重命名字段
{ $project: { fullName: "$name", age: 1 } }

// 计算新字段
{ $project: { total: { $multiply: ["$price", "$qty"] } } }

// 嵌套字段投影
{ $project: { "address.city": 1 } }

7.6 $unwind

7.6.1 作用

将数组字段拆分成多个文档,每个文档包含数组中的一个元素。常用于数组扁平化处理。

7.6.2 基本语法

javascript 复制代码
{ $unwind: "$items" }  // 拆解items数组

7.6.3 高级选项

javascript 复制代码
{
  $unwind: {
    path: "$tags",          // 要拆解的数组字段
    includeArrayIndex: "index", // 保存数组索引
    preserveNullAndEmptyArrays: true // 保留空数组或缺失字段的文档
  }
}

7.6.4 应用场景

  • 统计数组中每个元素的出现频率
  • 将嵌套数组数据展平以便后续聚合
  • 处理标签、评论等多值字段

7.7 数组表达式

7.7.1 常用数组操作符

  • $size:返回数组元素个数
  • $slice:截取数组部分元素
  • $arrayElemAt:获取指定索引的元素
  • $filter:过滤数组元素
  • $map:对数组每个元素应用表达式
  • $reduce:归约数组
  • $concatArrays:合并多个数组
  • $in:检查元素是否在数组中

7.7.2 示例

javascript 复制代码
{
  $project: {
    itemCount: { $size: "$items" },
    firstItem: { $arrayElemAt: ["$items", 0] },
    highValueItems: {
      $filter: {
        input: "$items",
        as: "item",
        cond: { $gt: ["$$item.price", 100] }
      }
    }
  }
}

7.8 累加器

7.8.1 概述

累加器用于在$group阶段对分组内的数据进行聚合计算。它们在文档流经管道时维护状态,直到分组完成。

7.8.2 常用累加器

累加器 说明 示例
$sum 求和 { $sum: "$amount" }
$avg 平均值 { $avg: "$score" }
$min / $max 最小值/最大值 { $min: "$price" }
$first / $last 第一个/最后一个值 { $first: "$name" }
$push 收集所有值到数组 { $push: "$product" }
$addToSet 收集唯一值到数组 { $addToSet: "$category" }
$stdDevPop / $stdDevSamp 标准差 { $stdDevPop: "$score" }

7.8.3 示例

javascript 复制代码
{
  $group: {
    _id: "$category",
    totalSales: { $sum: "$amount" },
    avgPrice: { $avg: "$price" },
    products: { $addToSet: "$productName" },
    count: { $sum: 1 }
  }
}

7.9 分组简介

7.9.1 $group阶段

$group是聚合框架中最核心的阶段之一,用于按指定字段分组,并对每组执行聚合计算。

7.9.2 基本语法

javascript 复制代码
{
  $group: {
    _id: <expression>,      // 分组依据
    <field1>: { <accumulator1>: <expression1> },
    <field2>: { <accumulator2>: <expression2> }
  }
}

7.9.3 分组依据

  • 单字段_id: "$category"
  • 多字段_id: { year: "$year", month: "$month" }
  • 常量_id: null(全局聚合)
  • 表达式_id: { $toUpper: "$city" }

7.9.4 示例

javascript 复制代码
db.orders.aggregate([
  {
    $group: {
      _id: { year: { $year: "$orderDate" }, status: "$status" },
      totalAmount: { $sum: "$amount" },
      orderCount: { $sum: 1 },
      avgAmount: { $avg: "$amount" }
    }
  },
  { $sort: { "_id.year": -1, totalAmount: -1 } }
]);

7.10 将聚合管道结果写入集合中

7.10.1 $out 阶段

将聚合结果写入指定的集合(会替换原有集合的内容)。

javascript 复制代码
db.orders.aggregate([
  { $match: { status: "completed" } },
  { $group: { _id: "$customerId", total: { $sum: "$amount" } } },
  { $out: "customer_totals" }
]);

7.10.2 $merge 阶段

更灵活的输出方式,可以将结果合并到现有集合(MongoDB 4.2+)。

javascript 复制代码
db.orders.aggregate([
  { $group: { _id: "$customerId", total: { $sum: "$amount" } } },
  {
    $merge: {
      into: "customer_summary",
      on: "_id",
      whenMatched: "replace",
      whenNotMatched: "insert"
    }
  }
]);

7.10.3 使用场景

  • 物化聚合结果,提升后续查询性能
  • 创建报表、仪表板数据源
  • 数据仓库ETL流程

总结

本章系统介绍了MongoDB聚合框架的核心内容:

类别 知识点
基础概念 管道、阶段、可调参数(allowDiskUse、explain)
常见阶段 match、match、match、sort、limit、limit、limit、skip、lookup、lookup、lookup、addFields
表达式 布尔、比较、条件、算术、字符串、日期、数组表达式
字段操作 $project(字段投影、计算、重命名)
数组处理 unwind(数组拆解)、数组表达式(unwind(数组拆解)、数组表达式(unwind(数组拆解)、数组表达式(filter、$map等)
聚合计算 累加器(sum、sum、sum、avg、push等)、push等)、push等)、group分组
结果输出 out(覆盖写入)、out(覆盖写入)、out(覆盖写入)、merge(合并写入)

聚合框架是MongoDB实现复杂数据分析的核心能力,掌握这些知识点能够帮助开发者高效处理数据聚合、报表统计、数据清洗等场景。

相关推荐
城数派2 小时前
2015-2024年我国1km分辨率逐日地表温度(LST)栅格数据
数据库·arcgis·信息可视化·数据分析·excel
今儿敲了吗2 小时前
算法复盘——前缀和
笔记·学习·算法
城数派2 小时前
中国全国土壤有机碳密度数据集(2010-2024年)
数据库·arcgis·信息可视化·数据分析·excel
鹓于2 小时前
CRX格式详解:安装、开发与反编译
数据库
IvorySQL3 小时前
PostgreSQL 技术日报 (3月28日)|零停机补丁、约束新特性、性能避坑全收录
数据库·postgresql·开源
smchaopiao3 小时前
数据库优化技巧详解:从LIMIT到索引的提升策略
数据库·oracle
啊我不会诶3 小时前
最小生成树
c++·笔记·学习·算法
清水白石0083 小时前
Python 编程全景解析:四大核心容器的性能较量、语义之美与高阶实战
开发语言·数据库·python
菜菜小狗的学习笔记3 小时前
黑马程序员Redis--实战篇(黑马点评)
数据库·redis·缓存