zoukankan      html  css  js  c++  java
  • mongoDB学习 mongo的聚合框架、join

    聚合框架详情 请参考官方文档 

    https://docs.mongodb.com/manual/aggregation/

    MongoDB 聚合框架(Aggregation Framework)是一个计算框架,它可以:

    作用在一个或几个集合上;

      • 对集合中的数据进行的一系列运算;

      • 将这些数据转化为期望的形式;

    从效果而言,聚合框架相当于 SQL 查询中的:

      • GROUP BY
      • LEFT OUTER JOIN
      • AS等
    整个聚合运算过程称为管道(Pipeline),它是由多个步骤(Stage)组成的
    每个管道:
      • 接受一系列文档(原始数据);
      • 每个步骤对这些文档进行一系列运算;
      • 结果文档输出给下一个步骤;

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

    常见的stage步骤

    步骤 作用 SQL等价运算符
    $match 过滤 WHERE
    $project 投影 AS
    $sort 排序 ORDER BY
    $group 分组 GROUP BY
    $skip/$limit 结果限制 SKIP/LIMIT
    $lookup 左外连接 LEFT OUTER JOIN

     常见步骤中的运算符

    $match $project $group
    $eq/$gt/$gte/$lt/$lte
    $and/$or/$not/$in
    $geoWithin/$intersect
    ……
    选择需要的或排除不需要的字段
    $map/$reduce/$filter
    $range
    $multiply/$divide/$substract/$add
    $year/$month/$dayOfMonth/$hour/$minute/$second
    ……
    $sum/$avg
    $push/$addToSet
    $first/$last/$max/$min
    ……

      其他功能

    步骤 作用 SQL等价运算符
    $unwind 展开数组 N/A
    $graphLookup 图搜索 N/A
    $facet/$bucket 分面搜索 N/A

    比如展开数据就有妙用,可以将内嵌文档展开为多行数据。

    使用示例:

      条件过滤步骤 $match

      投影步骤 $project

      展开数据步骤 $unwind

      分组聚合步骤 $group 

     

    mongoSQl特有步骤$bucket

    $bucket 和select 中的case when 比较像。

    $Facet组合$bucket

     

     数据样例

    计算到目前为止的所有订单的总销售额
    db.orders.aggregate([
          { $group:
              {
                _id: null,
                total: { $sum: "$total" }
              }
          }
    ])
    // 结果: // { "_id" : null, "total" : NumberDecimal("44019609") }
    查询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: {       
    // 计算总金额 sum(a+b) as grandTotal         grandTotal: { $add: ["$total", "$shippingFee"] },         count: 1,         _id: 0 }
          } ])
    // 结果: // { "count" : 5875, "grandTotal" : NumberDecimal("2636376.00") }

     join操作

    适用场景:

    一般情况下,设计合理的mongoDB的文档嵌套模型可以避免频繁适用join操作,但是还是有些场景,需要设计主表和关联表做join

    1. 内嵌文档数据多,可能上万条或者更多。

    2.内嵌文档数据量大,可能数 MB 或者超过 16MB,而且并非常用字段。 
    3.内嵌文档或数组元素会频繁修改,一直增长。

    mongoDB join的适用限制

    MongoDB 对使用引用的集合之间并无主外键检查
    MongoDB 使用聚合框架的 $lookup 来模仿关联查询
    $lookup 只支持 left outer join
    $lookup 的关联目标(from)不能是分片表

    example1:

    db.contacts.aggregate([
      {
        $lookup:
          {
            from: "groups",
            localField: "group_ids",
            foreignField: "group_id",
            as: "groups"
          }
      }
    ])
    //select a.xx from contacts a left join groups b on a.group_ids=b.group_id
    //as 是起的别名

    example2:

    //表1
    db.orders.insert([
       { "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
       { "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 },
       { "_id" : 3  }
    ])
    //表2
    db.inventory.insert([
       { "_id" : 1, "sku" : "almonds", description: "product 1", "instock" : 120 },
       { "_id" : 2, "sku" : "bread", description: "product 2", "instock" : 80 },
       { "_id" : 3, "sku" : "cashews", description: "product 3", "instock" : 60 },
       { "_id" : 4, "sku" : "pecans", description: "product 4", "instock" : 70 },
       { "_id" : 5, "sku": null, description: "Incomplete" },
       { "_id" : 6 }
    ])
    //join示例
    db.orders.aggregate([
       {
         $lookup:
           {
             from: "inventory",
             localField: "item",
             foreignField: "sku",
             as: "inventory_docs"
           }
      }
    ])

    返回结果

       "_id" : 1,
       "item" : "almonds",
       "price" : 12,
       "quantity" : 2,
       "inventory_docs" : [
          { "_id" : 1, "sku" : "almonds", "description" : "product 1", "instock" : 120 }
       ]
    }
    {
       "_id" : 2,
       "item" : "pecans",
       "price" : 20,
       "quantity" : 1,
       "inventory_docs" : [
          { "_id" : 4, "sku" : "pecans", "description" : "product 4", "instock" : 70 }
       ]
    }
    {
       "_id" : 3,
       "inventory_docs" : [
          { "_id" : 5, "sku" : null, "description" : "Incomplete" },
          { "_id" : 6 }
       ]
    }

    上面是一对一的关联,还有多对多的关联,详情参考  官方文档:

    传送门 https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/

  • 相关阅读:
    Vijos训练计划 1304回文数
    18.03.03 位运算作业三则
    18.03.01 codevs1014 装箱问题
    Wikioi 1020 孪生蜘蛛 Label:Floyd最短路
    TYVJ P1004 滑雪 Label:记忆化搜索
    洛谷 P1118 数字三角形游戏 Label:dfs
    TYVJ P1015 公路乘车 &&洛谷 P1192 台阶问题 Label:dp
    洛谷 P1147 连续自然数和 Label:等差数列
    洛谷 P1019 单词接龙 Label:dfs
    洛谷 P1025 数的划分 Label:dp
  • 原文地址:https://www.cnblogs.com/yanghaolie/p/13164367.html
Copyright © 2011-2022 走看看