MongoDB聚合查询解析:多维数据关联和聚合

什么是聚合查询

在真实的业务环境,我们的表/文档肯定不止一个,常常需要在多个表之间进行关联查询。那么在MongoDB 中如何做多张表的关联查询了,这就需要用到聚合查询。

MongoDB中聚合(aggregate) 操作将来自多个document的value组合在一起,并通过对分组数据进行各种操作处理,并返回计算后的数据结果,主要用于处理数据(诸如统计平均值,求和等)。有点类似sql语句中的 count(*)、group by,但聚合查询功能要更加强大。

有哪些聚合查询的方法

MongoDB提供了三种方式去执行聚合操作:

  • Pipeline 聚合管道
  • 单一目的聚合方法
  • Map-Reduce

不过从从MongoDB 5.0 开始,map-reduce 已被弃用。

聚合管道

聚合管道是由aggregation framework将文档进入一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的聚合结果。

如图所示:

上图的操作,代码如下:

php 复制代码
db.orders.aggregate([
  { $match: { status: "A" } },
  { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
  • $match阶段:通过status字段过滤出符合条件的Document(即是Status等于"A"的Document);
  • $group 阶段:按cust_id字段对Document进行分组,以计算每个唯一cust_id的金额总和。

相当于 SQL 中的以下语句:

vbnet 复制代码
select cust_id as _id, sum(amount) as total from orders where status like "%A%" group by cust_id;

管道操作符

MongoDB管道 功能描述 SQL操作/函数
$match 文档过滤器 where
$group 分组统计器 group by
$project 字段整形师:修改输入文档的结构(例如重命名,增加、删除字段等) select
$sort 对结果排序 order by
$limit 限制管道输出的结果个数 limit
$skip 跳过制定数量的结果,并且返回剩下的结果
处理数组类型字段
$lookup 实现类似JOIN操作 join
$addFields 新增计算字段
$bucket 数据分布分析

想象你在玩俄罗斯套娃:

  1. $match:先筛掉不想要的娃娃(文档过滤)
  2. $unwind:拆开大礼包(数组展开)
  3. $group:按颜色分类(分组统计)
  4. $project:给娃娃穿新衣服(字段重塑)

字段路径

字段路径 是访问文档中字段的特殊语法,使用 $ 前缀标识字段层级关系,支持访问嵌套结构和数组元素。

核心语法规则:

  1. 根字段$字段名
    例:$name 访问顶层name字段
  2. 嵌套字段$父字段.子字段
    例:$address.city 访问address对象中的city
  3. 数组元素
    $数组字段.子字段 → 访问数组内元素的子字段
    $数组字段[index] → 访问指定索引元素

文档结构:

css 复制代码
// orders集合文档示例
{
_id: 1,
order_no: "ORD202301",
items: [
    { product: "手机", price: 2999, qty: 2 },
    { product: "耳机", price: 399, qty: 1 }
  ],
customer: {
    name: "张三",
    vip_level: 3
  }
}

聚合管道应用:

php 复制代码
db.orders.aggregate([
  { $unwind: "$items" }, // 展开订单商品数组
  { $project: {
      order_id: "$order_no", // 重命名字段
      product_name: "$items.product", // 访问嵌套数组元素
      total_price: { 
        $multiply: ["$items.price", "$items.qty"] // 计算字段
      },
      is_vip: { 
        $cond: { if: { $gte: ["$customer.vip_level", 3] }, then: "是", else: "否" } // 条件判断
      }
  }},
  { $match: { 
    total_price: { $gt: 1000 }, // 过滤高价商品
    is_vip: "是"
  }}
])

输出结果:

css 复制代码
[  {    "_id": 1,    "order_id": "ORD202301",    "product_name": "手机",    "total_price": 5998,    "is_vip": "是"  }]

注意事项

  1. 严格区分大小写$Customer$customer
  2. 空值处理 :访问不存在的字段返回null
  3. 特殊字符 :字段名含.时需用$["field.name"]语法
  4. 性能影响:频繁访问深层嵌套字段可能影响查询速度

通过合理使用字段路径,可以像操作对象属性一样灵活处理文档数据,是构建高效聚合管道的基石!

单一目的聚合方法

单一目的聚合方法聚合单个集合中的文档。这些方法很简单,但缺乏聚合管道的功能。

方法 说明
db.collection.estimatedDocumentCount() 返回集合或视图中文档的近似数量
db.collection.count() 返回集合或视图中文档的数量
db.collection.distinct() 返回具有指定字段的不同值的文档数组

总结

聚合查询就像给你的MongoDB装上涡轮增压引擎,当你能熟练驾驭这个工具时,海量数据将不再是令人头疼的负担,而是等待挖掘的金矿。记住:优秀的开发者用find,卓越的数据工程师用aggregate

相关推荐
一张假钞32 分钟前
Python3操作MongoDB批量upsert
开发语言·数据库·python·mongodb
Beronhider1 小时前
SQLZoo-SELECT within SELECT Tutorial
数据库·sql·mysql·数据分析
atom goper2 小时前
Redis混合持久化
数据库·redis·mybatis
yqcoder2 小时前
MongoDB 的基本概念
数据库·mongodb
JavaGuide3 小时前
Spring 项目接入 DeepSeek,分享两种超简单的方式!
数据库·python·spring
Minxinbb3 小时前
MySQL 中可以通过添加主键来节省磁盘空间吗?(译文)
数据库·mysql·dba
qq_13948428824 小时前
springboot239-springboot在线医疗问答平台(源码+论文+PPT+部署讲解等)
java·数据库·spring boot·后端·spring·maven·intellij-idea
陈老师还在写代码5 小时前
讲解下MySql的外连接查询在SpringBoot中的使用情况
数据库·spring boot·mysql
思考的Joey5 小时前
MongoDB:打破数据枷锁的灵活数据库
数据库