mongodb聚合(mongodb聚合操作)

本篇文章给大家谈谈mongodb聚合,以及mongodb聚合操作对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

mongodb Aggregation聚合操作之$unwind

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

说明:

解析输入文档中的数组字段指历大,为每个元素输出一个文档。每个输出文档都是输入文档,数组字段的值被元素替换。如果字段值为null、缺失或数组为空,则$unwind不会输出文档。

语法:

{ $unwind: field path }

可以将文档传递给$unwind以指定各种行为选项。

{

  $unwind:

    {

      path: field path,

      includeArrayIndex: string,

      preserveNullAndEmptyArrays: boolean

    }

}

参数解析:

path:string类型,数组字段的字段路径。若要指定字段路径,请在字段名称前加上美元符号$并将其括在引号中。

includeArrayIndex:string类型,可选的。用于保存元素的数组索引的新字段的名称。新字段名称不能以美元符号$开头。

preserveNullAndEmptyArrays:boolean类型,可选的。如果为真,如果路径为空、丢失或数组为空,则$unwind输出文档。如果为false,如果路径为空、丢失或数组为空,则$unwind不输出文档。默认值为false。

初始化数据:

db.inventory.insertOne({ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })

示例:按照sizes字段拆分数据

db.inventory.aggregate( [ { $unwind : "$sizes" } ] )

结果:

{ "_id" : 1, "item" : "ABC1", "sizes" : "S" }

{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }

{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }

初始化数据:

db.inventory2.insertMany([

  { "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] },

  { "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] },

  { "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" },

  { "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") },

  { "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null }

])

示例:

下烂指面的$unwind操作是等效的,并为size字段中的每个元素返回一个文档。如果size字段没唯竖有解析为数组,但没有丢失、null或空数组,则$unwind将非数组操作数视为单个元素数组。

db.inventory2.aggregate( [ { $unwind: "$sizes" } ] )

db.inventory2.aggregate( [ { $unwind: { path: "$sizes" } } ] )

结果:

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" }

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" }

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" }

{ "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" }

示例:下面的$unwind操作使用includeArrayIndex选项在输出中包含数组索引。

db.inventory2.aggregate( [

  {

    $unwind:

      {

        path: "$sizes",

         includeArrayIndex : "arrayIndex"

      }

   }])

结果:

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S", " arrayIndex " : NumberLong(0) }

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M", " arrayIndex " : NumberLong(1) }

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L", " arrayIndex " : NumberLong(2) }

{ "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M", " arrayIndex " : null }

示例:下面的$unwind操作使用preserveNullAndEmptyArrays选项来包含size字段为null、缺失或空数组的文档。

db.inventory2.aggregate( [

   { $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }

] )

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" }

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" }

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" }

{ "_id" : 2, "item" : "EFG", "price" : NumberDecimal("120") }

{ "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" }

{ "_id" : 4, "item" : "LMN", "price" : NumberDecimal("10") }

{ "_id" : 5, "item" : "XYZ", "price" : NumberDecimal("5.75"), "sizes" : null }

初始化数据:

db.inventory2.insertMany([

  { "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] },

  { "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] },

  { "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" },

  { "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") },

  { "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null }

])

示例:下面的管道将展开大小数组,并将产生的文档按展开后的大小值进行分组:

db.inventory2.aggregate( [

   // First Stage

   {

     $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true }

   },

   // Second Stage

   {

     $group:

       {

         _id: "$sizes",

         averagePrice: { $avg: "$price" }

       }

   },

   // Third Stage

   {

     $sort: { "averagePrice": -1 }

   }

] )

结果:

{ "_id" : "M", "averagePrice" : NumberDecimal("120") }

{ "_id" : "L", "averagePrice" : NumberDecimal("80") }

{ "_id" : "S", "averagePrice" : NumberDecimal("80") }

{ "_id" : null, "averagePrice" : NumberDecimal("45.25") }

初始化数据:

db.sales.insertMany([

  {

    _id: "1",

    "items" : [

     {

      "name" : "pens",

      "tags" : [ "writing", "office", "school", "stationary" ],

      "price" : NumberDecimal("12.00"),

      "quantity" : NumberInt("5")

     },

     {

      "name" : "envelopes",

      "tags" : [ "stationary", "office" ],

      "price" : NumberDecimal("1.95"),

      "quantity" : NumberInt("8")

     }

    ]

  },

  {

    _id: "2",

    "items" : [

     {

      "name" : "laptop",

      "tags" : [ "office", "electronics" ],

      "price" : NumberDecimal("800.00"),

      "quantity" : NumberInt("1")

     },

     {

      "name" : "notepad",

      "tags" : [ "stationary", "school" ],

      "price" : NumberDecimal("14.95"),

      "quantity" : NumberInt("3")

     }

    ]

  }

])

示例:下面的操作将按标签销售的商品分组,并计算每个标签的总销售额。

db.sales.aggregate([

  // First Stage

  { $unwind: "$items" },

  // Second Stage

  { $unwind: "$items.tags" },

  // Third Stage

  {

    $group:

      {

        _id: "$items.tags",

        totalSalesAmount:

          {

            $sum: { $multiply: [ "$items.price", "$items.quantity" ] }

          }

      }

  }

])

结果:

{ "_id" : "writing", "totalSalesAmount" : NumberDecimal("60.00") }

{ "_id" : "stationary", "totalSalesAmount" : NumberDecimal("264.45") }

{ "_id" : "electronics", "totalSalesAmount" : NumberDecimal("800.00") }

{ "_id" : "school", "totalSalesAmount" : NumberDecimal("104.85") }

    { "_id" : "office", "totalSalesAmount" : NumberDecimal("1019.60") }

MongoDB 轻松搞定统计 —— 聚合函数使用

在 MySQL 中我们通常使用 SELECT count(*) FROM table_name WHERE ... 来获取满足某个条件的记录条数。在 MondoDB 中还提供了类似的方法。MongoDB 有如下方式:

以下面的数据为例:

查找男性的用户数量可以这样做:

如果要实现条件查询呢,使用条件即可,比如查询性别为男,年龄大于等于15的用户:

条件的时候和之前条件查询的用法一样,可以参考: MongoDB 条件查询和排序 。

MongoDB 同样提供了分组计数的方法。比如要统计男女性别的人数,可以按如下方式进行:

求和通过聚合的$sum 操作符来完成,可以笑段用来计算某一个数值列的和,例如我们要计算所有年龄之和。

这里_id 指定为 null 是就是对全部数据进行求和(即不散脊分组),若指定了列,则可以分组求和,比如对男性和女性分别求和。

求和也可以对多个字段进行求和,以下面的外卖订单冲升渗数据为例:

我们想知道算上配送费的订单总额,可以像下面那样做,如果我们加上商品名称也可以得到每个商品的销售总额。

平均值通过$avg 操作符完成,例如上面数据的计算平均客单价:

本篇介绍了 MongoDB 的聚合函数的基本用法,包括计数、求和和取平均值。通过 MongoDB 提供了聚合函数可以高效地完成统计工作。

[img]

mongoDB表与表的关系及聚合管道查询

MongoDB 中的关系可以是:

MongoDB 聚合管道(Aggregation Pipeline)

使用聚合管道可以对集合中的文档进行变换和组合。

管道操作符

$project 修改文档的结构,可以用来重命名、增加或删除文档中的谈羡字段。

$match 用于过滤文档。用法类似于 find() 方法中的参数。

$limit 用来限制MongoDB聚合管道返回的文档数

$skip 在聚合管羡侍祥道中跳过指定数量的文档,并返回余下的文档。兄搏

$sort 将输入文档排序后输出

$group 将集合中的文档进行分组,可用于统计结果

$lookup 可以引用其他集合的数据(表关联查询)

创建数据

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字段外,指定输出文档中要包含的字段的文档。要指定要包含的字段,必须使用累加器表达式。

初始化数据:

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

        }

    ]

}

可以使用$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' } ] } ] } ]

mongodb Aggregation聚合操作之$sort

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

说明:

 对所有输入文档进行排序,并将它们按排序顺序返回到管道。

语法:

 { $sort: { field1: sort order, field2: sort order ... } }

$sort接收一个文档,该文档指定要排序的字段和相应的排序顺序。排序顺序可以有以下值之一:

1:升序排序

-1:降序排序

{ $meta: "textScore" }:按计算的textScore元数据降序排序。

注意【如果对多个字段进行排序,则从左者弯搏到右计算排序顺序。例如,在上面的表单中,文档首先按field1排序。然后,具有相同field1值的文档按field2进一步排序。】示例

对于要排序的字段或字段,将排序顺序设置为1或-1,分别指定升序或降序排序,如下例所示:该操作对users集合中的文档进行排序,根据age字段降序排列,然后根据posts字段中的值升序排列。

db.users.aggregate(

   [

     { $sort : { age : -1, posts: 1 } }

   ]

)

在{sort-key}文档中指定计算出的元数据的新字段名,并指定$meta表达式作为它的值,如下面的示例所示:该操作使用$text操作符匹配文档,然后首先按“textScore”元数据排序,然后按posts字段的降序排序。指定的元数据决定排序顺序。例如,“textScore”元数据按降序排序。

db.users.aggregate(

   [

     { $match: { $text: { $search: "operating" } } },

   首祥  { $sort: { score: { $meta: "textScore" }, posts: -1 } }

   ]

)

$sort + $limit内存优化

当$sort在$limit之前并且没有修改文档数量的中间阶段时,优化器可以将$limit合并到$sort中。这允许$sort操作在进行过程中只维护顶部的n个结果,其中n是指定的限制,并确保MongoDB只需要在内存中存储n个项目。当allowDiskUse为true且n项超过聚合内存限制时,这种优化仍然适用。优化可能会在不同版本之间发生变化。

$sort阶段的RAM有100兆字节的限制。默认情况下,如果阶段超过这个限制,$sort将产生一个错误。为了允许处理大型数据集,将allowDiskUse选项设置为true,以允许$sort操作写入临时文件。有关详细信息,请参阅db.collection.aggregate()方法中的allowDiskUse选项和aggregate命令。

版本2.6中的变化:$sort的内存限制从RAM的10%更改为100兆字节。

如果将$sort操作符放置在管道的开闹谈头,或放置在$project、$unwind和$group聚合操作符之前,则可以利用索引。如果$project、$unwind或$group发生在$sort操作之前,则$sort不能使用任何索引

关于mongodb聚合和mongodb聚合操作的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

标签列表