mongodb Aggregation聚合操作之$bucket

在上一篇mongodb Aggregation聚合操作之$facet中详细介绍了mongodb聚合操作中的$facet使用以及参数细节。本篇将开始介绍Aggregation聚合操作中的$bucket操作。

说明:

根据指定的表达式和bucket边界将传入的文档分类到称为bucket的组中,并为每个bucket输出一个文档。每个输出文档都包含一个_id字段,其值指定bucket的包含下界。输出选项指定每个输出文档中包含的字段。

$bucket只为至少包含一个输入文档的bucket生成输出文档。


语法:

{

  $bucket: {

      groupBy: <expression>,

      boundaries: [ <lowerbound1>, <lowerbound2>, ... ],

      default: <literal>,

      output: {

         <output1>: { <$accumulator expression> },

         ...

         <outputN>: { <$accumulator expression> }

      }

   }

}


参数讲解:

groupBy:用来对文档进行分组的表达式。要指定字段路径,请在字段名称前加上美元符号$并将其括在引号中。除非$bucket包含默认规范,否则每个输入文档必须将groupBy字段路径或表达式解析为属于边界指定的范围之一的值。

boundaries:一个基于groupBy表达式的值数组,该表达式指定每个bucket的边界。每一对相邻的值充当桶的包含下边界和独占上边界。您必须指定至少两个边界。

default:可选的。指定附加bucket的_id的文字,该bucket包含groupBy表达式结果不属于边界指定的bucket的所有文档。如果未指定,则每个输入文档必须将groupBy表达式解析为由边界指定的bucket范围中的一个值,否则操作将抛出错误。默认值必须小于最低边界值,或大于或等于最高边界值。

默认值可以是与边界项不同的类型。

output:可选的。除_id字段外,指定输出文档中要包含的字段的文档。要指定要包含的字段,必须使用累加器表达式。

1. 示例

1.1. 单bucket示例


初始化数据:

db.artists.insertMany([

  { "_id" : 1, "last_name" : "Bernard", "first_name" : "Emil", "year_born" : 1868, "year_died" : 1941, "nationality" : "France" },

  { "_id" : 2, "last_name" : "Rippl-Ronai", "first_name" : "Joszef", "year_born" : 1861, "year_died" : 1927, "nationality" : "Hungary" },

  { "_id" : 3, "last_name" : "Ostroumova", "first_name" : "Anna", "year_born" : 1871, "year_died" : 1955, "nationality" : "Russia" },

  { "_id" : 4, "last_name" : "Van Gogh", "first_name" : "Vincent", "year_born" : 1853, "year_died" : 1890, "nationality" : "Holland" },

  { "_id" : 5, "last_name" : "Maurer", "first_name" : "Alfred", "year_born" : 1868, "year_died" : 1932, "nationality" : "USA" },

  { "_id" : 6, "last_name" : "Munch", "first_name" : "Edvard", "year_born" : 1863, "year_died" : 1944, "nationality" : "Norway" },

  { "_id" : 7, "last_name" : "Redon", "first_name" : "Odilon", "year_born" : 1840, "year_died" : 1916, "nationality" : "France" },

  { "_id" : 8, "last_name" : "Diriks", "first_name" : "Edvard", "year_born" : 1855, "year_died" : 1930, "nationality" : "Norway" }

])


示例:

db.artists.aggregate( [

  // First Stage

  {

    $bucket: {

      groupBy: "$year_born",  // 按year_born字段分组

      boundaries: [ 1840, 1850, 1860, 1870, 1880 ], // 桶的边界

      default: "Other",  // 不属于Bucket的文档的Bucket id【如果一个文档不包含year_born字段,或者它的year_born字段在上面的范围之外,那么它将被放在_id值为“Other”的默认bucket中。】

      output: {  //输出

        "count": { $sum: 1 },

        "artists" :

          {

            $push: {

              "name": { $concat: [ "$first_name", " ", "$last_name"] },

              "year_born": "$year_born"

            }

          }

      }

    }

  },

  // 筛选结果大于3的

  {

    $match: { count: {$gt: 3} }

  }

] )


结果是:

{

    "_id" : 1860.0, //桶的包含下界。

    "count" : 4.0,//桶中文档的计数。

    "artists" : [ //包含bucket中每个艺术家信息的文档数组。每个文档都包含了艺术家的name,它是艺术家的first_name和last_name的连接(即$concat)

        {

            "name" : "Emil Bernard",

            "year_born" : 1868.0

        },

        {

            "name" : "Joszef Rippl-Ronai",

            "year_born" : 1861.0

        },

        {

            "name" : "Alfred Maurer",

            "year_born" : 1868.0

        },

        {

            "name" : "Edvard Munch",

            "year_born" : 1863.0

        }

    ]

}


1.2. 使用带有$facet的$bucket,通过多个字段实现bucket


可以使用$facet阶段在单个阶段中执行多个$bucket聚合。


初始化数据:

db.artwork.insertMany([

  { "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926,

      "price" : NumberDecimal("199.99") },

  { "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902,

      "price" : NumberDecimal("280.00") },

  { "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925,

      "price" : NumberDecimal("76.04") },

  { "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai",

      "price" : NumberDecimal("167.30") },

  { "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931,

      "price" : NumberDecimal("483.00") },

  { "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913,

      "price" : NumberDecimal("385.00") },

  { "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893

      /* No price*/ },

  { "_id" : 8, "title" : "Blue Flower", "artist" : "O'Keefe", "year" : 1918,

      "price" : NumberDecimal("118.42") }

])


示例:下面的操作使用$facet阶段中的两个$bucket阶段创建两个分组,一个按价格,另一个按年:

db.artwork.aggregate( [

  {

    $facet: {    // 顶级$facet stage

      "price": [ // Output field 1

        {

          $bucket: {

              groupBy: "$price",            // Field to group by

              boundaries: [ 0, 200, 400 ],  // Boundaries for the buckets

              default: "Other",             // Bucket id for documents which do not fall into a bucket

              output: {                     // Output for each bucket

                "count": { $sum: 1 },

                "artwork" : { $push: { "title": "$title", "price": "$price" } },

                "averagePrice": { $avg: "$price" }

              }

          }

        }

      ],

      "year": [                                      // Output field 2

        {

          $bucket: {

            groupBy: "$year",                        // Field to group by

            boundaries: [ 1890, 1910, 1920, 1940 ],  // Boundaries for the buckets

            default: "Unknown",                      // Bucket id for documents which do not fall into a bucket

            output: {                                // Output for each bucket

              "count": { $sum: 1 },

              "artwork": { $push: { "title": "$title", "year": "$year" } }

            }

          }

        }

      ]

    }

  }

] )


结果:

[ { price:

     [ { _id: 0,

         count: 4,

         artwork:

          [ { title: 'The Pillars of Society',

              price:

               { _bsontype: 'Decimal128',

                 bytes: <Buffer 1f 4e 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> } },

            { title: 'Dancer',

              price:

               { _bsontype: 'Decimal128',

                 bytes: <Buffer b4 1d 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> } },

            { title: 'The Great Wave off Kanagawa',

              price:

               { _bsontype: 'Decimal128',

                 bytes: <Buffer 5a 41 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> } },

            { title: 'Blue Flower',

              price:

               { _bsontype: 'Decimal128',

                 bytes: <Buffer 42 2e 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> } } ],

         averagePrice:

          { _bsontype: 'Decimal128',

            bytes: <Buffer d7 6d 15 00 00 00 00 00 00 00 00 00 00 00 38 30> } },

       { _id: 200,

         count: 2,

         artwork:

          [ { title: 'Melancholy III',

              price:

               { _bsontype: 'Decimal128',

                 bytes: <Buffer 60 6d 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> } },

            { title: 'Composition VII',

              price:

               { _bsontype: 'Decimal128',

                 bytes: <Buffer 64 96 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> } } ],

         averagePrice:

          { _bsontype: 'Decimal128',

            bytes: <Buffer e2 81 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> } },

       { _id: 'Other',

         count: 2,

         artwork:

          [ { title: 'The Persistence of Memory',

              price:

               { _bsontype: 'Decimal128',

                 bytes: <Buffer ac bc 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> } },

            { title: 'The Scream' } ],

         averagePrice:

          { _bsontype: 'Decimal128',

            bytes: <Buffer ac bc 00 00 00 00 00 00 00 00 00 00 00 00 3c 30> } } ],

    year:

     [ { _id: 1890,

         count: 2,

         artwork:

          [ { title: 'Melancholy III', year: 1902 },

            { title: 'The Scream', year: 1893 } ] },

       { _id: 1910,

         count: 2,

         artwork:

          [ { title: 'Composition VII', year: 1913 },

            { title: 'Blue Flower', year: 1918 } ] },

       { _id: 1920,

         count: 3,

         artwork:

          [ { title: 'The Pillars of Society', year: 1926 },

            { title: 'Dancer', year: 1925 },

            { title: 'The Persistence of Memory', year: 1931 } ] },

       { _id: 'Unknown',

         count: 1,

         artwork: [ { title: 'The Great Wave off Kanagawa' } ] } ] } ]

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容