MongoDB 分组统计

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介:    MongoDB 作为 NoSql 文档型数据库,在全球范围得到广泛的支持与应用。在比较常用的数据库功能中,相对于普通的增删改查,使用 group 聚合分组统计有些复杂,而 MongoDB 也给予了支持。

   MongoDB 作为 NoSql 文档型数据库,在全球范围得到广泛的支持与应用。在比较常用的数据库功能中,相对于普通的增删改查,使用 group 聚合分组统计有些复杂,而 MongoDB 也给予了支持。本文将对MongoDb分组的实现方法及示例进行分析,通过在 MongoDB 脚本中操作、使用集算器 SPL 语言操作两种操作途径,进行简单的归纳总结。具体的问题场景包括以下几个方面:

  1. 内嵌数组结构的统计........................................................................... 1
  2. 内嵌文档求和..................................................................................... 2
  3. 分段分组结构统计.............................................................................. 4
  4. 多字段分组统计................................................................................. 6
  5. 内嵌数组结构的统计
    对嵌套数组结构中的数据进行统计处理例如查询考试科目的平均分及每个学生的总成绩:

测试数据:
1
00

由于各科分数 scroe 是按课目、成绩记录的数组结构,统计前需要将它拆解,将每科成绩与学生对应,然后再实现分组计算。这需要熟悉 unwind 与 group 组合的应用。
2
脚本说明:
       A1:连接 mongodb 数据库。
       A2:获取 student 表中的数据。
       A3:将 scroe 数据合并成序表,再按课程分组,计算平均分。
       A4:统计每个学生的成绩后返回列名为 NAME、TOTAL 的序表。new 函数表示生成新序表。
       A5:关闭数据库连接。

   这个嵌套结构统计的例子比较常见,相信很多人都遇到过,需要先拆解再分组计算,主要是熟悉 mongodb 对嵌套数据结构的处理。

  1. 内嵌文档求和
    对内嵌文档中的数据求和处理, 例如统计下面每条记录中 income,output 的数量和。

测试数据:
3
Mongodb脚本:
var fields = [  "income", "output"];
db.computer.aggregate([ 
   { 
      $project:{ 
         "values":{ 
            $filter:{ 
               input:{ 
                    "$objectToArray":"$$ROOT"
               },
               cond:{ 
                  $in:[ 
                     "$$this.k",
                     fields
                  ]
               }
            }
         }
      }
   },
   { 
      $unwind:"$values"
   },
   { 
      $project:{ 
         key:"$values.k",
         values:{ 
            "$sum":{ 
               "$let":{ 
                  "vars":{ 
                     "item":{ 
                          "$objectToArray":"$values.v"
                     }
                  },
                    "in":"$$item.v"
               }
            }
         }
      }
   },
   {$sort: {"_id":-1}},
   { "$group": {
    "_id": "$_id",
    'income':{"$first":   "$values"},
    "output":{"$last":   "$values"}
    }},
]);
oe 是按课目、成绩记录的数组结构,统计前需要将它拆解,将每科成绩与学生对应,然后再实现分组计算。这需要熟悉 unwind 与 group 组合的应用。
SPL 脚本 (student.dfx):
filter将income,output 部分信息存放到数组中,用 unwind 拆解成记录,再累计各项值求和,按 _id 分组合并数据。

SPL脚本:
3
脚本说明:
      A1:连接数据库
      A2:获取 computer 表中的数据
      A3:将 income、output 字段中的数据分别转换成序列求和,再与 ID 组合生成新序表
      A4:关闭数据库连接。

   获取子记录的字段值,然后求和,相对于 mongo 脚本简化了不少。这个内嵌文档与内嵌数组在组织结构上有点类似,不小心容易混淆,因此需要特别注意与上例中的 scroe 数组结构比较,写出的脚本有所不同。

  1. 分段分组结构统计
    统计各段内的记录数量。例如下面按销售量分段,统计各段内的数据量,数据如下:

4
Mongo 脚本
var a_count=0;
var b_count=0;
var c_count=0;
var d_count=0;
var e_count=0;
db.sales.find({
}).forEach(
    function(myDoc) {
        if (myDoc.SALES <3000)   {
            a_count += 1;
        }
        else if (myDoc.SALES <5000)   {
            b_count += 1;
        }
        else if (myDoc.SALES   <7500) {
            c_count += 1;
        }
        else if (myDoc.SALES   <10000) {
            d_count += 1;
        }
        else {
            e_count += 1;
        }       
    }
    );
   
print("a_count="+a_count)
print("b_count="+b_count)
print("c_count="+c_count)
print("d_count="+d_count)
print("e_count="+e_count)
这个需求按条件分段分组,mongodb 没有提供对应的 api,实现起来有点繁琐,上面的程序是其中实现的一个例子参考,当然也可以写成其它实现形式。下面看看集算器脚本的实现。

SPL脚本:
5
脚本说明:
       A1:定义 SALES 分组区间。
       A2:连接 mongodb 数据库。
       A3:获取 sales 表中的数据。
       A4:根据 SALES 区间分组统计员工数。其中函数 pseg()表示返回成员在序列中的区段序号,int() 表示转换成整数。
       A5:关闭数据库连接。

     Mongodb脚本与 SPL 脚本都实现了预期的结果,但函数pseg 的使用让 SPL 脚本精简了不少。

  1. 多字段分组统计
    统计分类项下的总数及各子项数。下面统计按 addr 分类的 book 的数量以及其下不同 book 类型的数量。

6
Mongo脚本
db.books.aggregate([
    {   "$group": {
      "_id": {
     
"addr": "$addr",
  "book": "$book"
},
"bookCount": {"$sum": 1}
    }},
    {   "$group": {
  "_id": "$_id.addr",
"books": {
              "$push": {
                  "book": "$_id.book",
                  "count": "$bookCount"
            },
        },
          "count": {"$sum": "$bookCount"}
    }},
    {"$sort":   { "count": -1} },
    {   "$project": {
          "books": {"$slice": [ "$books", 2] },
          "count": 1
    }}
]).pretty()
先按 addr,book 分组统计 book 数,再按 addr 分组统计 book 数,调整显示顺序。

SPL脚本 (books.dfx):
8
脚本说明:
        A1:连接 mongodb 数据库。
        A2:获取 books 表中的数据。
        A3:按 addr,book 分组统计 book 数顾。
        A4:再按 addr 分组统计 book 数。
        A5:将 A4 中的 Total 按 addr 关联后合并到序表中。
        B5: 返回序表 A5。
        A6:关闭数据库连接。

   这个例子中的 SPL 脚本除了一如既往的精简清晰外,还显示了如何简单方便地与 Java 程序集成。

   在 Java 程序中如果要对 MongoDB 实现上面的分组统计功能,需要根据不同的需求重新一五一十地实现,比较麻烦的同时也不通用。而如果用集算器来实现就容易多了,集算器提供了 JDBC 驱动程序,支持在 Java 程序中用 JDBC 存储过程方式访问计算结果,调用方法与调用存储过程相同。(JDBC 具体配置参考《集算器教程》中的“JDBC基本使用”章节)
       Java 调用主要过程如下:
       public void testStudent (){
              Connection con = null;
              com.esproc.jdbc.InternalCStatement st;
       try{
             // 建立连接
             Class.forName("com.esproc.jdbc.InternalDriver");
             con= DriverManager.getConnection("jdbc:esproc:local://");
             //调用存储过程,其中books是 dfx 的文件名
             st =(com. esproc.jdbc.InternalCStatement)con.prepareCall("call books ()");
             //执行存储过程
             st.execute();
             // 获取结果集
             ResultSet rs = st.getResultSet();
              。。。。。。。
       catch(Exception e){
             System.out.println(e);
       }
可以看到,集算器的计算结果能够很方便地供 Java 应用程序使用。除了上面的调用方式,程序也可以修改成直接加载 SPL 脚本的函数,用 SPL 脚本文件名当参数来实现。同时,集算器也支持 ODBC 驱动,与其它支持 ODBC 的语言集成也与此类似。

   简单总结一下,MongoDB 的聚合分组计算的操作与存储文档的结构息息相关,丰富的文档结构一方面有利于存储,同时数据查询展示也可以做到多样化,但另一方面也带来了 shell 脚本操作的复杂性,写起来比较不容易, 需要考虑的细节、步骤也比较多。通过上面这几个简单案例的分析比较,可以看到集算器 SPL 在实现分组统计方面能简化操作,降低难度,从而有效地帮助我们解决问题。

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
NoSQL MongoDB
11 MongoDB - 数据查询(统计个数)
11 MongoDB - 数据查询(统计个数)
871 0
|
SQL NoSQL 关系型数据库
MongoDB复杂分组聚合查询1
MongoDB复杂分组聚合查询1
534 0
|
NoSQL MongoDB
mongodb 分组查询、指定时间段查询
mongodb 分组查询、指定时间段查询
|
分布式计算 JavaScript 前端开发
MongoDB复杂分组聚合查询3
MongoDB复杂分组聚合查询3
135 0
|
SQL NoSQL 关系型数据库
MongoDB复杂分组聚合查询2
MongoDB复杂分组聚合查询2
116 0
|
编解码 NoSQL 数据可视化
MongoDB——聚合数组大小做统计
前段时间做统计,我们的平台数据库用的mongodb,其中有一个统计需求如下:需要查询每个用户的转码个数(对应的素材,每个素材可能有多个转码)
|
NoSQL MongoDB
MongoDB aggregate聚合分组查询
MongoDB aggregate聚合分组查询
305 0
|
NoSQL 前端开发 Java
SpringBoot集成spring-data-mongodb 技术点记录 --分组分页查询
SpringBoot集成spring-data-mongodb 技术点记录 --分组分页查询
740 0
|
NoSQL Java MongoDB
mongodb命令行group分组和java代码中group分组
group分组统计是数据库比较常用的功能,mongodb也不例外。不过相对于普通的增删改查,group操作就略微麻烦一些, 这里对group在shell中的操作、使用java原生代码操作以及集成spring进行操作进行一个简单的归纳总结,分组的途径和方法应该都有多种,这里每一样只举一例。 本例中数据源如下: 需要使用group实现的目的是:按年龄分组统计出每一组的数量。 1、mo
5937 0