ITPub博客

首页 > 数据库 > > mongo.Aggregate.倚天剑.剑走偏锋

mongo.Aggregate.倚天剑.剑走偏锋

作者:浪花小雨滴 时间:2020-05-22 10:25:43 0 删除 编辑

热爱武侠的人一定读过金庸老先生写的“倚天屠龙记”,宝刀屠龙,号令天下,莫敢不从,前4篇「Mongo存储和性能优化」所展示的,可以说是屠龙刀,而现在我们即将描述的Aggregate就是倚天剑,倚天不出,谁也争锋..

倚天剑里面所藏武功,就是九阴白骨爪,下面让我们一起来修行这个高深莫测的武功,废话就到此为止,开始练功。

使用聚合框架可以对集合中文档进行变化和组合,可以用多个构件创建一个管道,用于对一连串的文档进行处理,构件有筛选,投影,分组,排序等。

  • 下面介绍管道表达式,管道表达式可以理解为一个KV的结构,其中管道操作符作为“Key”,所对应的“Value”叫做管道表达式。例如{$match:{name:”zhangsan”}},$match称为管道操作符,而{name:”zhangsan”}称之为管道表达式,它称之为管道操作符的操作数(Operand),每个管道表达式是一个文档结构,它是由字段名、字段值、和一些表达式操作符组成的,例如管道表达式$group: { _id: null, count: { $avg: 1 } } 就包含了一个表达式操作符$avg算平均值。
  • 每个管道表达式只能作用于处理当前正在处理的文档,而不能进行跨文档的操作。管道表达式对文档的处理都是在内存中进行的。除了能够进行累加计算的管道表达式外,其他的表达式都是无状态的,也就是不会保留上下文的信息,累加性质的表达式操作符通常和$group操作符一起使用,来统计该组内最大值、最小值等。
  • 语法结构: db.collection.aggregate(pipeline,options) , pipeline 「数据的聚合操作」,Options「explain,allowDiskUse,cursor,maxTimeMS,bypassDocumentValidation,readConcern」 具体的详细信息,点击查看官网文
  • 当aggregate返回的结果集(指针或者结果集),当结果集中的单个文档超过16 MB命令会报错;该限制只适用于返回的结果集文档,在管道处理文档的过程中,这个文档很有可能会超过16MB;
  • 如果使用aggregate不指定游标选项或存储集合中的结果,aggregate命令返回一个包涵于结果集的字段中的bson文件。如果结果集的总大小超过bson文件大小限制(16MB)该命令将产生错误;
  • 管道处理阶段有内存限制最大不能超过100MB,超过这个限制会报错误;为了能够处理更大的数据集可以开启allowDiskUse选项,可以将管道操作写入临时文件;

下面着重介绍其中的管道操作符号:

  • 九阴白骨爪之$match

简介:通过指定的条件来过滤文档,然后传给下一个管道

语法:{ $match: { <query> } }

 数据源
{ "_id" : ObjectId("512bc95fe835e68f199c8686"), "author" : "dave", "score" : 80, "views" : 100 }
{ "_id" : ObjectId("512bc962e835e68f199c8687"), "author" : "dave", "score" : 85, "views" : 521 }
{ "_id" : ObjectId("55f5a192d4bede9ac365b257"), "author" : "ahn", "score" : 60, "views" : 1000 }
{ "_id" : ObjectId("55f5a192d4bede9ac365b258"), "author" : "li", "score" : 55, "views" : 5000 }
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b259"), "author" : "annT", "score" : 60, "views" : 50 }
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b25a"), "author" : "li", "score" : 94, "views" : 999 }
{ "_id" : ObjectId("55f5a1d3d4bede9ac365b25b"), "author" : "ty", "score" : 95, "views" : 1000 }

查询语句
db.articles.aggregate(
    [ { $match : { author : "dave" } } ]
);

结果:
{ "_id" : ObjectId("512bc95fe835e68f199c8686"), "author" : "dave", "score" : 80, "views" : 100 }
{ "_id" : ObjectId("512bc962e835e68f199c8687"), "author" : "dave", "score" : 85, "views" : 521 }

参考文章:

$match (aggregation)​docs.mongodb.com图标
  • 九阴白骨爪之$project

简介:传给下一个管道所需要的字段,字段包含输入文档存在的字段和新的计算字段

语法:{ $project: { <specification(s)> } }

数据源
{
  "_id" : 1,
  title: "abc123",
  isbn: "0001122223334",
  author: { last: "zzz", first: "aaa" },
  copies: 5
}
查询语句
db.books.aggregate( [ { $project : { title : 1 , author : 1 } } ] )
输出结果
{ "_id" : 1, "title" : "abc123", "author" : { "last" : "zzz", "first" : "aaa" } }   

参考文章:

$project (aggregation)​docs.mongodb.com图标


  • 九阴白骨爪之$group

简介:按照指定的表达式来对文档进行分组,然后按照每一个分组传给下一个管道,最后输出对文档包含_id作为分组对Key,输出对文档也包含计算的字段的值。

语法:{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }

数据源
{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-03-01T08:00:00Z") }
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-03-01T09:00:00Z") }
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-03-15T09:00:00Z") }
{ "_id" : 4, "item" : "xyz", "price" : 5, "quantity" : 20, "date" : ISODate("2014-04-04T11:21:39.736Z") }
{ "_id" : 5, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-04-04T21:23:13.331Z") }
查询语句
db.sales.aggregate(
   [
      {
        $group : {
           _id : { month: { $month: "$date" }, day: { $dayOfMonth: "$date" }, year: { $year: "$date" } },
           totalPrice: { $sum: { $multiply: [ "$price", "$quantity" ] } },
           averageQuantity: { $avg: "$quantity" },
           count: { $sum: 1 }
        }
      }
   ]
)
输出结果
{ "_id" : { "month" : 3, "day" : 15, "year" : 2014 }, "totalPrice" : 50, "averageQuantity" : 10, "count" : 1 }
{ "_id" : { "month" : 4, "day" : 4, "year" : 2014 }, "totalPrice" : 200, "averageQuantity" : 15, "count" : 2 }
{ "_id" : { "month" : 3, "day" : 1, "year" : 2014 }, "totalPrice" : 40, "averageQuantity" : 1.5, "count" : 2 }

参考文章

$group (aggregation)​docs.mongodb.com图标


  • 九阴白骨爪之$unwind

简介:将输入文档中的数组,分割成对应的一个文档,数组中的一个值对应一个文档

语法:{
$unwind:
{
path: <field path>,
includeArrayIndex: <string>,
preserveNullAndEmptyArrays: <boolean>
}
}

数据源
{ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] }

查询语句
db.inventory.aggregate( [ { $unwind : "$sizes" } ] )

输出结果
{ "_id" : 1, "item" : "ABC1", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }

参考文章

https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/​docs.mongodb.com
  • 九阴白骨爪之$limit
    简介:限制传递给下一个管道的文档数量

语法:{ $limit: <positive integer> }

db.article.aggregate(
    { $limit : 5 }
);

参考文章:

$limit (aggregation)​docs.mongodb.com图标
  • 九阴白骨爪之$skip

简介:跳过指定数量的文档,传递剩余的文档到下一个管道

语法:{ $skip: <positive integer> }

db.article.aggregate(
    { $skip : 5 }
);

参考文章

$skip (aggregation)​docs.mongodb.com图标
  • 九阴白骨爪之$sort

简介:排序所有的文档传给下一个管道

语法 :{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }

db.users.aggregate(
   [
     { $sort : { age : -1, posts: 1 } }
   ]
)

参考文章

$sort (aggregation)​docs.mongodb.com图标
  • 九阴白骨爪之$lookup

简介:在同一个数据库执行左外连接,来过滤相关的文档,传递给下一个管道

语法:{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}

数据源:
db.orders.insert([
   { "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 },
   { "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 },
   { "_id" : 3  }
])
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 }
])
查询语句:
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 }
   ]
}

参考文章

$lookup (aggregation)​docs.mongodb.com图标
  • 九阴白骨爪之$count

简介:统计文档的数量传递给下一个管道

语法:{ $count: <string> }

数据源
{ "_id" : 1, "subject" : "History", "score" : 88 }
{ "_id" : 2, "subject" : "History", "score" : 92 }
{ "_id" : 3, "subject" : "History", "score" : 97 }
{ "_id" : 4, "subject" : "History", "score" : 71 }
{ "_id" : 5, "subject" : "History", "score" : 79 }
{ "_id" : 6, "subject" : "History", "score" : 83 }
查询语句
db.scores.aggregate(
  [
    {
      $match: {
        score: {
          $gt: 80
        }
      }
    },
    {
      $count: "passing_scores"
    }
  ]
)
输出结果
{ "passing_scores" : 4 }

参考文章

$count (aggregation)​docs.mongodb.com图标
  • 九阴白骨爪之$redact

简介:根据文档本身存储的信息来限制文档

语法:{ $redact: <expression> }

数据源
{
  _id: 1,
  title: "123 Department Report",
  tags: [ "G", "STLW" ],
  year: 2014,
  subsections: [
    {
      subtitle: "Section 1: Overview",
      tags: [ "SI", "G" ],
      content:  "Section 1: This is the content of section 1."
    },
    {
      subtitle: "Section 2: Analysis",
      tags: [ "STLW" ],
      content: "Section 2: This is the content of section 2."
    },
    {
      subtitle: "Section 3: Budgeting",
      tags: [ "TK" ],
      content: {
        text: "Section 3: This is the content of section3.",
        tags: [ "HCS" ]
      }
    }
  ]
}
查询语句
var userAccess = [ "STLW", "G" ];
db.forecasts.aggregate(
   [
     { $match: { year: 2014 } },
     { $redact: {
        $cond: {
           if: { $gt: [ { $size: { $setIntersection: [ "$tags", userAccess ] } }, 0 ] },
           then: "$$DESCEND",
           else: "$$PRUNE"
         }
       }
     }
   ]
);
输出结果
{
  "_id" : 1,
  "title" : "123 Department Report",
  "tags" : [ "G", "STLW" ],
  "year" : 2014,
  "subsections" : [
    {
      "subtitle" : "Section 1: Overview",
      "tags" : [ "SI", "G" ],
      "content" : "Section 1: This is the content of section 1."
    },
    {
      "subtitle" : "Section 2: Analysis",
      "tags" : [ "STLW" ],
      "content" : "Section 2: This is the content of section 2."
    }
  ]
}

参考文章

$redact (aggregation)​docs.mongodb.com图标


九阴白骨爪果真是门邪恶的武功,头痛无比,夜已深,在写非得走火入魔,下期再见 九阴白骨爪.横扫千军.....

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3126810/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2018-05-16

  • 博文量
    4259
  • 访问量
    39968