zoukankan      html  css  js  c++  java
  • MongoDB入门实战教程(6)

    本系列教程目录:

    MongoDB入门实战教程(1)

    MongoDB入门实战教程(2)

    MongoDB入门实战教程(3)

    MongoDB入门实战教程(4)

    MongoDB入门实战教程(5)

    通过前面几篇的学习,作为后端开发的我们基本可以应付70%的开发场景。接下来,我们就来看点进阶一点的东西,首先是聚合查询。

    1 聚合框架简介

    前面的学习我们都是针对单个Collection操作的,虽然在MongoDB中针对Collection的设计就已经是无模式的,因此我们大部分场景都是针对单个Collection进行操作。

    但是,我们在实际应用场景中还是会遇到想要SQL查询中的 GROUP BY、LEFT OUTER JOIN、AS等操作。

    好在,MongoDB提供了一套聚合框架(Aggregation Framework),它可以帮助我们在一个或多个Collection上,对Collection中的数据进行一系列的计算,并将这些数据转化为期望的格式。

    整个聚合计算的过程也被称之为管道(Pipeline),由多个步骤(Stage)组成,这一点和Jenkins Pipeline比较类似。其中,每个管道需要:

    (1)接受一系列Document(原始数据)

    (2)每个步骤对这些Document进行一系列的运算

    (3)结果Document输出给下一个步骤

    整个管道的过程如下图所示:

    聚合计算的基本格式如下所示:

    pipeline = [$stage1, $stage2, ...$stageN];
    
    db.<CollectionName>.aggregate(
    pipeline,
    { options }
    );

    2 聚合操作实例

    示例数据数据库

    这里我们使用《MongoDB入门实战教程(3)》中使用Mongo Tools进行恢复的Mock数据库中的orders集合来进行应用。

    在orders集合中,约有100000条记录。

    每个order文档的数据模型如下所示:

    练习1:目前为止的订单总销量

    假设我们需要针对orders集合进行一个操作,计算到目前为止的所有订单的总销售额:

    db.orders.aggregate([
      { $group:
        {
          _id: null,
          total: { $sum: "$total" }
        }
      }
    ]);

     这里我们使用到了一个常见的步骤(Stage):$group,它和SQL中的GROUP BY等价,用于对数据进行分组。这里我们仅仅是做一个求和,不需要对谁进行分组。

    然后,我们还用到了一个分组步骤中常用的运算符:$sum,它和SQL中的SUM等价,用于对指定列的数据进行求和。这里我们需要对total字段进行一个求和。

    下图是查询结果:

    练习2:某个日期区间的订单金额汇总

    假设我们需要查询在2019年第一季度已完成订单的订单总金额和订单总数。

    说明:第一季度为1月1日~3月31日,订单状态为completed。

    db.orders.aggregate([
    // 步骤1:匹配条件
    { $match: { status: "completed", orderDate: {
                                    $gte: ISODate("2019-01-01"),
                                    $lt: ISODate("2019-04-01") } } },
    // 步骤二:聚合订单总金额、总运费、总数量
    { $group: {
                  _id: null,
                  total: { $sum: "$total" },
                  shippingFee: { $sum: "$shippingFee" },
                  count: { $sum: 1 } } },
    { $project: {
                  // 计算总金额
                  grandTotal: { $add: ["$total", "$shippingFee"] },
                  count: 1,
                  _id: 0 } }
    ])

    可以看到,这是一个较为复杂的查询,我们可以将其分为三步:

    第一步,使用$match进行匹配,这一点是做的SQL中的WHERE操作。

    第二步,使用$group进行分组,目的是为了使用SUM运算符求和。

    第三步,使用$project进行投影,目的是选择需要的或排除不需要的字段显示。

    下图是查询结果:

    3 MQL vs SQL

    分页查询对比

    在SQL中常使用SKIP 和 LIMIT 进行分页查询,在MQL中也有等价操作:

    -- SQL
    SELECT
      FIRST_NAME AS `名`,
      LAST_NAME AS `姓`
    FROM Users
    WHERE GENDER = ''
    SKIP 100
    LIMIT 20
    -- MQL
    db.users.aggregate([
      {$match: {gender: ""}},
      {$skip: 100},
      {$limit: 20},
      {$project: {
        '': '$first_name',
        '': '$last_name'
      }}
    ]);

    分组查询对比

    在SQL中常使用GROUP BY + HAVING 的分组高级查询,在MQL中也有等价操作:

    -- SQL
    SELECT DEPARTMENT,
      COUNT(NULL) AS EMP_QTY
    FROM Users
    WHERE GENDER = ''
    GROUP BY DEPARTMENT HAVING
    COUNT(*) < 10
    -- MQL
    db.users.aggregate([
      {$match: {gender: ''}},
      {$group: {
        _id: '$DEPARTMENT’,
        emp_qty: {$sum: 1}
      }},
      {$match: {emp_qty: {$lt: 10}}}
    ]);

    unwind

    在MQL中有一个特有的步骤 unwind,它可以实现将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。

    > db.students.findOne()
    {
      name:'张三',
      score:[
        {subject:'语文',score:84},
        {subject:'数学',score:90},
        {subject:'外语',score:69}
      ]
    }
    
    > db.students.aggregate([{$unwind: '$score'}])
    {name: '张三', score: {subject: '语文', score: 84}}
    {name: '张三', score: {subject: '数学', score: 90}}
    {name: '张三', score: {subject: '外语', score: 69}}

    4 总结

    本文简单介绍了MongoDB的Aggregation Framework 以及 如何使用聚合框架进行聚合查询。

    下一篇,我们会学习MongoDB的模式设计中的一些设计模式。

    参考资料

    Microsoft Doc,使用ASP.NET Core和MongoDB创建WebAPI

    唐建法,《MongoDB高手课》(极客时间)

    郭远威,《MongoDB实战指南》(图书)

    △推荐订阅学习

  • 相关阅读:
    判断是否是微信浏览器
    弹性盒模型
    一个发光的搜索边框(纯CSS3)
    小练习
    js控制div是否显示
    遮罩弹窗
    布局
    CSS构造表单
    CSS 滤镜(IE浏览器专属其他浏览器不支持)
    Css中光标,DHTML,缩放的使用
  • 原文地址:https://www.cnblogs.com/edisonchou/p/mongodb_learning_summary_part6.html
Copyright © 2011-2022 走看看