MongoDB聚合:分组统计$group的用法详解

MongoDB不像关系型数据库,普通的查询不支持汇总,要进行复杂的分组汇总,需要使用聚合管道,$group可以说是MongoDB聚合管道进行数据分析最常用的一个阶段。该阶段根据分组键值(组键)把文档分成若干组,每个唯一的键值对应一个文档。组键通常是一个或多个字段,也可以是表达式的结果。$group阶段输出的结果中,_id字段的值就是组键的值,输出文档中还可以包含汇总表达式的字段,汇总表达式的功能非常丰富,下面的列表会简单介绍,具体的使用方法可以参考详细说明。

$group的语法

{
 $group:
   {
     _id: <expression>, // 组键,就是分组的键值字段或表达式
     <field1>: { <accumulator1> : <expression1> },
     ...
   }
 }

字段说明:

字段 说明
_id 不可省略,通过_id表达式指定分组的依据,如果直接指定_id的值为null或常量,则把全部的输入文档汇总后返回一个文档
field 可选,汇总表达式计算的结果
_id和field可以是任何合法的表达式。

分组汇总操作符

分组汇总操作符比较多,功能丰富且强大,这里简要介绍其用途,详细的用法后续再专文介绍。

操作符 用途介绍
$accumulator 返回累加结果
$addToSet 把分组中不重复的表达式的值作为数组返回,注意数组的元素无序的,类似分组内的distinct
$avg 返回数值的平均值。非数值会被忽略
$bottom 按照指定的顺序返回分组中最后一个元素
$bottomN 按照指定的顺序返回分组中最后N个元素字段的集合,如果分组元素数量小于N,则返回全部
$count 返回分组内的元素数量
$first 返回分组内第一个元素表达式的结果
$firstN 返回分组内前n个元素的聚合。只有文档有序时才有意义
$last 返回分组中最后一个文档的表达式的结果
$lastN 返回分组内最后n个元素的聚合。只有文档有序时才有意义
$max 返回每个分组表达式值的最大值
$maxN 返回分组内最大的n个元素的集合
$median 返回分组中的中位数
$mergeObjects 返回分组合并后的文档
$min 返回分组内表达式的最小值
$percentile 返回与指定百分位数值相对应的值的数组
$push 返回每个分组表达式值的数组
$stdDevPop 返回标准差
$stdDevSamp 返回样本标准差
$sum 返回合计值,忽略空值
$top 根据指定的顺序返回组内最前面的元素
$topN 根据指定的顺序返回组内前N个元素的聚合

注意

  1. $group使用内存不能超过100M,超过会报错。如果想要处理更多数据或者少用一些内存,可使用allowDiskUse选项把数据写入临时文件。
  2. 当使用$first、$last等操作符时,可以考虑在参与排序的分组字段上添加索引,某些情况下,这些操作可以使用索引快速定位到相应的记录。

一些例子

统计数量

创建并插入数据:

db.sales.insertMany([
  { "_id" : 1, "item" : "abc", "price" : Decimal128("10"), "quantity" : Int32("2"), "date" : ISODate("2014-03-01T08:00:00Z") },
  { "_id" : 2, "item" : "jkl", "price" : Decimal128("20"), "quantity" : Int32("1"), "date" : ISODate("2014-03-01T09:00:00Z") },
  { "_id" : 3, "item" : "xyz", "price" : Decimal128("5"), "quantity" : Int32( "10"), "date" : ISODate("2014-03-15T09:00:00Z") },
  { "_id" : 4, "quantity" :  Int32("20") , "date" : ISODate("2014-04-04T11:21:39.736Z") },
  { "_id" : 5, "quantity" : Int32("10") , "date" : ISODate("2014-04-04T21:23:13.331Z") },
  { "_id" : 6, "item" : "def", "price" : Decimal128("7.5"), "quantity": Int32("5" ) , "date" : ISODate("2015-06-04T05:08:13Z") },
  { "_id" : 7, "quantity": Int32("10") , "date" : ISODate("2015-09-10T08:43:00Z") },
  { "_id" : 8, "quantity" : Int32("5" ) , "date" : ISODate("2016-02-06T20:20:13Z") },
])
统计sales全部文档数量

相当于collection.find({}).count()

db.sales.aggregate( [
  {
    $group: {
       _id: null,
       count: { $count: { } }
    }
  }
] )

结果:

{ "_id" : null, "count" : 8 }
检索不同的值,等价于distinct

仍以上例的sales集合数据为例

db.sales.aggregate( [ { $group : { _id : "$item" } } ] )

结果:

{ "_id" : "abc" }
{ "_id" : "jkl" }
{ "_id" : "def" }
{ "_id" : "xyz" }

等价于:

db.sales.distinct("item")
按Item分组

下面的聚合先按照item进行分组,计算每个item销售总额,并且返回大于等于100的item。

db.sales.aggregate(
  [
    //阶段1
    {
      $group :
        {
          _id : "$item",
          totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } }
        }
     },
     //阶段2
     {
       $match: { "totalSaleAmount": { $gte: 100 } }
     }
   ]
 )

阶段1:
$group阶段,根据item进行分组,并计算每个item的销售总额。
阶段2:
$math阶段,过滤结果文档,只返回销售总额totalSaleAmount大于等于100的文档。
结果:

{ "_id" : "abc", "totalSaleAmount" : Decimal128("170") }
{ "_id" : "xyz", "totalSaleAmount" : Decimal128("150") }
{ "_id" : "def", "totalSaleAmount" : Decimal128("112.5") }

计算总数、合计和平均值

创建一个sales集合并插入记录:

db.sales.insertMany([
  { "_id" : 1,
])
按照日期分组

下面的聚合管道计算2014年的销售总额、平均销量和销售数量

db.sales.aggregate([
  //阶段1
  {
    $match : { "date": { $gte: new ISODate("2014-01-01"), $lt: new ISODate("2015-01-01") } }
  },
  //阶段2
  {
    $group : {
       _id : { $dateToString: { format: "%Y-%m-%d", date: "$date" } },
       totalSaleAmount: { $sum: { $multiply: [ "$price", "$quantity" ] } },
       averageQuantity: { $avg: "$quantity" },
       count: { $sum: 1 }
    }
  },
  //阶段3
  {
    $sort : { totalSaleAmount: -1 }
  }
 ])

阶段1
使用$math只允许2014年的数据进入下一阶段.
阶段2
使用$group根据日期进行分组,统计每个分组的销售总额、平均销量和销售数量。
阶段3
使用$sort按照销售总额进行降序排序
结果:

{
   "_id" : "2014-04-04",
   "totalSaleAmount" : Decimal128("200"),
   "averageQuantity" : 15, "count" : 2
}
{
   "_id" : "2014-03-15",
   "totalSaleAmount" : Decimal128("50"),
   "averageQuantity" : 10, "count" : 1
}
{
   "_id" : "2014-03-01",
   "totalSaleAmount" : Decimal128("40"),
   "averageQuantity" : 1.5, "count" : 2
}
按控制null分组

下面的聚合操作,指定分组_id为空,计算集合中所有文档的总销售额、平均数量和计数。

db.sales.aggregate([
  {
    $group : {
       _id : null,
       count: { $sum: 1 }
    }
  }
 ])

结果:

{
  "_id" : null,
  "totalSaleAmount" : Decimal128("452.5"),
  "averageQuantity" : 7.875,
  "count" : 8
}

数据透视

创建books集合并插入数据

db.books.insertMany([
  { "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 },
  { "_id" : 8752, "title" : "Divine Comedy", "copies" : 1 },
  { "_id" : 8645, "title" : "Eclogues",
  { "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 },
  { "_id" : 7020, "title" : "Iliad", "copies" : 10 }
])
根据作者对标题分组

下面的聚合操作将books集合中的数据透视为按作者分组的标题。

db.books.aggregate([
   { $group : { _id : "$author", books: { $push: "$title" } } }
 ])

结果

{ "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] }
{ "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }
根据作者对文档分组
db.books.aggregate([
   // 阶段1
   {
     $group : { _id : "$author", books: { $push: "$$ROOT" } }
   },
   // 阶段2
   {
     $addFields:
       {
         totalCopies : { $sum: "$books.copies" }
       }
   }
 ])

阶段1:
分组$group,根据作者对文档进行分组,使用$$ROOT把文档作为books的元素。
阶段2:
$addFields会在输出文档中添加一个字段,即每位作者的图书总印数。
结果:

{
  "_id" : "Homer",
  "books" :
     [
       { "_id" : 7000,
       { "_id" : 7020, "copies" : 10 }
     ],
   "totalCopies" : 20
}

{
  "_id" : "Dante",
  "books" :
     [
       { "_id" : 8751,
       { "_id" : 8752,
       { "_id" : 8645, "copies" : 2 }
     ],
   "totalCopies" : 5
}

以上内容参考mongodb官方文档整理而来
如果这篇文章对你有用,可点赞、收藏,让它帮助更多人

原文地址:https://blog.csdn.net/superatom01/article/details/135004991

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读552次。com.mongodb.MongoQueryException: Query failed with error code 292 and error message 'Executor error during find command :: caused by :: Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting.' on server 11.51.141.63:27017 _mongodb 大文件 下载失败
文章浏览阅读635次,点赞9次,收藏8次。MongoDB 是一种 NoSQL 数据库,它将每个数据存储为一个文档,这里的文档类似于 JSON/BSON 对象,具体数据结构由键值(key/value)对组成。
文章浏览阅读2.1k次。和。_mongodb 日期类型
文章浏览阅读1.7k次。Scalestack等客户期待使用MongoDB Atlas Vector Search和Amazon Bedrock构建下一代应用程序
文章浏览阅读970次。SpringBoot整合中间件mongodb、ES_springboot3 elasticsearch json数据
文章浏览阅读673次。MongoDB 简介_尚医通sql
文章浏览阅读1k次,点赞8次,收藏9次。官网下载MongoDB安装包后进行解压(因了解并不深入,故暂不进行详细说明,自行查找其他安装方法,后期了解深入后将进行该教程的完善)在bin目录下使用命令启动:./mongod --config …/mongodb.conf。该文章任然处于完善中,如果存在错误遗漏的地方,欢迎私信联系。安装相关的nuget包后即可通过以下方法连接数据。YX9010_0@的第二十篇文章。
文章浏览阅读1.2k次,点赞17次,收藏26次。社交场景, 使用 MongoDB 存储存储用户信息, 以及用户发表的朋友圈信息, 通过地理位置索引实现附近的人, 地点等功能.游戏场景, 使用 MongoDB 存储游戏用户信息, 用户的装备, 积分等直接以内嵌文档的形式存储, 方便查询, 高效率存储和访问.物流场景, 使用 MongoDB 存储订单信息, 订单状态在运送过程中会不断更新, 以 MongoDB 内嵌数组的形式来存储, 一次查询就能将订单所有的变更读取出来.物联网场景, 使用 MongoDB 存储所有接入的智能设备信息, 以及设备汇报的日
文章浏览阅读686次。您可以使用 update_one() 方法来更新 MongoDB 中调用的记录或文档。update_one() 方法的第一个参数是 query 对象,用于定义要更新的文档。注释:如果查询找到多个记录,则仅更新第一个匹配项。第二个参数是定义文档新值的对象。_python 更新 mongodb 数据
文章浏览阅读1.3k次。首先来学习一下nosql这里安装就不进行介绍 只记录一下让自己了解mongodb。_nosql注入
文章浏览阅读4.1k次,点赞8次,收藏7次。在data的目录下,创建一个db文件。因为启动MongoDB服务之前必须创建数据库文件的存放文件夹,否则命令不会自动创建,而且不能启动成功。第一步:安装时,Custom是指可以自定义安装路径,然后傻瓜式安装即可(注意:先不要安装图形化工具,否则安装时间会特别长):如果要想连接成功,必须要开服务,即mongod -dbpath C:MongoDBdatadb的cmd要一直开着。然后回车,ctrl+F输入port找到端口号,一般为:27017。打开命令行,然后找到bin文件地址,并输入。_mongodb windows安装
文章浏览阅读5.1k次,点赞3次,收藏43次。详细介绍MongoDB数据库的基本知识,安装方法,基本操作,_mongodb数据库
文章浏览阅读3.2k次。安装教程翻看以往文章。_navicat 连接mongodb
文章浏览阅读426次,点赞9次,收藏12次。win10开放端口:https://blog.csdn.net/m0_43605481/article/details/119255256。我的是阿里云服务器,所以直接在安全组中加入规则,端口范围:27017,授权对象:0.0.0.0。windows在mongodb安装文件夹的bin文件夹中的mongod.cfg。数据库名字是test,打算创建一个用户,账号aaa,密码bbb,权限readWrite。因为该用户是创建在test数据库的,所以在最后要加上test。O了,然后恢复了test的数据。
文章浏览阅读1.1k次。聚合操作主要用于处理数据并返回计算结果。聚合操作将来自多个文档的值组合在一起,按条件分组后,再进行一系列操作(如求和、平均值、最大值、最小值)以返回单个结果。MongoDB的聚合查询​聚合是MongoDB的高级查询语言,它允许我们通过转化合并由多个文档的数据来生成新的在单个文档里不存在的文档信息。MongoDB中聚合(aggregate)主要用于处理数据(例如分组统计平均值、求和、最大值等),并返回计算后的数据结果,有点类似sql语句中的count(*)、groupby。..._如何将几个db的数据统整在一起做查询
文章浏览阅读680次,点赞7次,收藏8次。(2)application.properties配置文件。(4)UserService类。(5)测试和测试结果。
文章浏览阅读1k次,点赞17次,收藏25次。Studio 3T 2023.9 (macOS, Linux, Windows) - MongoDB 的专业 GUI、IDE 和 客户端,支持自然语言查询_mongodb客户端
文章浏览阅读1.1k次,点赞32次,收藏27次。插件式的存储引擎架构可以实现 Server 层和存储引擎层的解耦,可以支持多种存储引擎,如 MySQL 既可以支持 B-Tree 结构的 InnoDB 存储引擎,还可以支持 LSM 结构的 RocksDB 存储引擎。MongoDB 中的记录就是一个 BSON 文档,它是由键值对组成的数据结构,类似于 JSON 对象,是 MongoDB 中的基本数据单元。的简称,是 JSON 文档的二进制表示,支持将文档和数组嵌入到其他文档和数组中,还包含允许表示不属于 JSON 规范的数据类型的扩展。
文章浏览阅读5.1k次,点赞6次,收藏96次。本文设计了一种基于智能室内温度控制的自动调速风扇。以STM32系列单片机为核心主控板,通过程序代码驱动和使用温度传感器模块实现对环境温度的实时监测,并可以实时显示环境温度。同时,可以设置温度检测的上下警告值,根据需求自行调节。_stm32 温控风扇
文章浏览阅读898次,点赞13次,收藏21次。在MongoDB中,我们使用find()和find_one()方法来在集合中查找数据,就像在MySQL数据库中使用SELECT语句来在表中查找数据一样。_pymongo find_one