深入浅出:MongoDB聚合管道技术的全面解析与实战指南

文摘   科技   2024-10-04 18:49   湖北  


  • 一、聚合管道介绍

    • 1. 流水线处理

    • 2. 阶段(Stages)

    • 3. 操作符(Operators)

    • 4. 数据处理流程

    • 5. 输出结果

  • 二、聚合管道的使用

  • 三、聚合管道的常见场景


一、聚合管道介绍

聚合管道是MongoDB中用于数据聚合和处理的强大工具。通过一系列有序的阶段(Stages)对数据进行筛选、转换、分组和计算,从而生成符合需求的聚合结果。每个阶段都定义了一种操作,数据在每个阶段经过处理后,传递给下一个阶段,最终得到所需的聚合结果。

在聚合管道中,每个阶段都使用特定的操作符来定义操作。这些操作符包括筛选操作符(如$match)、分组操作符(如$group)、排序操作符(如$sort)等。可以根据需要选择合适的操作符,组合成满足需求的聚合管道。

理解聚合管道的原理对于有效地使用MongoDB进行数据查询和数据分析至关重要:

1. 流水线处理

聚合管道采用流水线处理模式,数据从输入通过一个接一个的阶段处理,达到最终输出。每个阶段都负责执行特定的操作,如筛选、分组、排序等。

2. 阶段(Stages)

聚合管道由多个阶段组成,每个阶段都定义了对数据执行的操作。这些阶段是有序的,数据按照定义的顺序流经每个阶段。每个阶段都可以使用不同的操作符来执行不同的操作。

3. 操作符(Operators)

操作符是定义在聚合管道阶段中的指令,如$match操作符用于筛选文档,$group操作符用于将文档分组,$project操作符用于选择或计算新的字段等。这些操作符提供了丰富的功能,使得聚合管道能够执行各种复杂的数据处理任务。

常见的聚合管道操作符

  • $match: 用于筛选文档,类似于find方法。
  • $group: 用于根据某个字段对文档进行分组,并可以计算每个分组的统计信息,如总和、平均值等。
  • $sort: 用于对文档进行排序。
  • $project: 用于选择或计算新的字段,可以重命名、增加或删除字段。
  • $unwind: 用于将数组类型的字段拆分成多条记录。
  • $limit: 用于限制输出结果的数量。
  • $lookup: 用于进行表连接操作,可以在一个集合中根据外键查询另一个集合的数据。

4. 数据处理流程

先从指定的集合中读取数据。然后数据会按照定义的顺序流经每个阶段并接受相应的操作:如筛选、分组、排序等。结果传递给下一个阶段,直到所有数据都经过所有阶段的处理。

5. 输出结果

通常,聚合管道的输出结果是一个包含处理后的文档的游标(Cursor),可以遍历游标。还可使用聚合管道的输出阶段(如$out)将结果直接写入另一个集合中。

二、聚合管道的使用

使用聚合管道进行数据分析的基本步骤:

  1. 构建聚合管道:根据需求选择合适的阶段和操作符,构建聚合管道。每个阶段都定义了数据的处理方式,如筛选、分组、排序等。
  2. 执行聚合管道:将构建好的聚合管道作为参数传递给MongoDB的aggregate()方法,执行聚合操作。执行过程中,数据会按照定义的顺序流经每个阶段,每个阶段都会对数据进行相应的处理。
  3. 处理聚合结果:聚合操作完成后,会得到一个包含聚合结果的游标(Cursor)。可以遍历游标。

一个orders的订单集合。每个订单都有一个customer_idproduct_idorder_date(订单日期)和amount(订单金额)。我们的需求是进行以下分析:

  1. 计算每个产品的总销售额。
  2. 计算每个客户在每个产品上的平均订单金额。
  3. 找到平均订单金额最高的前5名客户,并列出他们购买的所有产品。

为了实现这些需求,我们使用多个聚合阶段,包括$group$sort$limit$lookup

db.orders.aggregate([
  // 第一阶段:按产品和客户分组,计算每个产品和客户的总销售额
  {
    $group: {
      _id: { product_id"$product_id"customer_id"$customer_id" },
      totalSales: { $sum"$amount" }
    }
  },
  
  // 第二阶段:再次按产品和客户分组,计算每个客户在每个产品上的平均订单金额
  {
    $group: {
      _id"$_id.customer_id",
      productSales: {
        $push: {
          productId"$_id.product_id",
          avgAmount: { $avg"$totalSales" }
        }
      },
      totalSales: { $sum"$totalSales" } // 计算每个客户的总销售额
    }
  },
  
  // 第三阶段:根据平均订单金额降序排序,并限制结果为前5名客户
  {
    $sort: {
      "productSales.avgAmount"-1
    }
  },
  
  {
    $limit5
  },
  
  // 第四阶段:使用$lookup将客户ID关联到客户集合,以获取客户信息
  // 假设有一个名为customers的集合,其中包含客户详细信息
  {
    $lookup: {
      from"customers",
      localField"_id",
      foreignField"customer_id",
      as"customerDetails"
    }
  },
  
  // 第五阶段:展开客户详细信息数组,准备输出结果
  {
    $unwind: {
      path"$customerDetails",
      includeArrayIndex"index",
      preserveNullAndEmptyArraystrue
    }
  },
  
  // 第六阶段:按客户ID分组,列出每个客户购买的所有产品及其平均订单金额
  {
    $group: {
      _id"$_id",
      customerName: { $first"$customerDetails.name" },
      customerEmail: { $first"$customerDetails.email" },
      products: {
        $push: {
          productId"$productSales.productId",
          avgAmount"$productSales.avgAmount"
        }
      }
    }
  },
  
  // 第七阶段:按客户名称排序输出结果
  {
    $sort: {
      customerName1
    }
  }
])

这个聚合管道的工作流程:

  1. 第一个$group阶段按产品和客户ID分组,计算每个产品和客户的总销售额。
  2. 第二个$group阶段再次按客户ID分组,计算每个客户在每个产品上的平均订单金额,并计算每个客户的总销售额。
  3. 第三个和第四个$sort$limit阶段将结果按平均订单金额降序排序,并限制输出为前5名客户。
  4. 第五个$lookup阶段将客户ID与客户集合中的详细信息关联起来。
  5. 第六个$unwind阶段展开客户详细信息数组,为每个客户创建一个文档。
  6. 最后一个$group阶段按客户ID分组,列出每个客户购买的所有产品及其平均订单金额。
  7. 最后的$sort阶段按客户名称对结果进行排序。

三、聚合管道的常见场景

  1. 数据分组统计:根据某个字段对数据进行分组,并计算每个分组的统计信息,如总数、平均值、最大值等。
  2. 数据筛选和过滤:使用筛选操作符对数据进行筛选,只保留满足条件的数据。
  3. 数据排序:根据某个字段对数据进行排序,得到有序的数据集。
  4. 数据转换和计算:使用投影操作符对数据进行转换和计算,生成新的字段或计算值。

太强 ! SpringBoot中出入参增强的5种方法 : 加解密、脱敏、格式转换、时间时区处理

太强 ! SpringBoot中优化if-else语句的七种绝佳方法实战

SpringBoot使用EasyExcel并行导出多个excel文件并压缩zip下载
提升编程效率的利器: Google Guava库中双向映射BitMap
从MySQL行格式原理看:为什么开发规范中不推荐NULL?数据是如何在磁盘上存储的?
SpringBoot中使用Jackson实现自定义序列化和反序列化控制的5种方式总结
提升编程效率的利器: Google Guava库之RateLimiter优雅限流
深入JVM逃逸分析原理:且看其如何提高程序性能和内存利用率
必知必会!MySQL索引下推:原理与实战

深入解析JVM内存分配优化技术:TLAB

SpringBoot中基于JWT的双token(access_token+refresh_token)授权和续期方案
SpringBoot中基于JWT的单token授权和续期方案
SpringBoot中Token登录授权、续期和主动终止的方案(Redis+Token)
微服务中token鉴权设计的4种方式总结
提升编程效率的API利器:精通Google Guava库区间范围映射RangeMap
SpringBoot中Jackson控制序列化和反序列化的注解和扩展点总结【收藏版】

SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载

SpringBoot中基于XXL-JOB实现大量数据灵活控制的分片处理方案

关注『 码到三十五 』,日有所获
                     点赞 和 在看 就是最大的支持

码到三十五
主要分享正经的开发技术(原理,架构,实践,源码等),以输出驱动输入;当然偶尔会穿插点生活琐碎,顺便吃个瓜,目的嘛,搞点精准流量,看能不能发发广告。
 最新文章