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/

 

posted @ 2020-06-19 17:56  Nucky_yang  阅读(902)  评论(0编辑  收藏  举报