MongoDB 高级查询-分组聚合的实践篇

有很多时候大量日志类流水的数据存储到mongodb或者elasticsearch中,既然是数据肯定要去分析统计出我们需要的数据才是有用的数据,不然跟咸鱼没有什么区别。下面来讲讲如何运用mongodb的聚合函数(aggregate)完成sql语句中group by常规数据统计,以及常规数据查询。
MongoDB中聚合(aggregate)主要用于统计数据(比如统计平均值( a v g ) , 求 和 ( avg),求和( avg,(sum) ,最大最小( m i n , min, min,max)等分组函数),并view计算后的统计结果。由于方便学习下面语句中省略的表达式我都写出来。


aggregate() 方法的使用

如何应用这个方法,首先我们还得了解方法的主要层级关系,我列出了一个图如下:

聚合查询层级图

1、 m a t c h 对 象 就 是 s q l 中 的 w h e r e 条 件 比 如 查 询 名 字 为 王 小 明 , 在 本 月 购 买 金 额 在 200 − 300 之 间 的 数 据 , 这 个 语 句 怎 么 来 写 , 首 先 我 们 来 分 析 一 下 里 面 有 三 组 条 件 ( 名 字 n a m e , 时 间 a d d T i m e , 金 额 m o n e y ) , 条 件 关 系 是 ( 与 a n d ) 。 定 义 一 个 match 对象就是sql 中的where 条件 比如查询名字为王小明,在本月购买金额在200-300之间的数据,这个语句怎么来写,首先我们来分析一下里面有三组条件(名字name,时间addTime,金额money),条件关系是(与and)。定义一个 matchsqlwhere200300nameaddTimemoney,(and)match 条件关系定义一个 a n d , and , and,and(或条件可以用$or)后面跟三个条件( name,addTime, money) 组成的数组。具体语句如下图:
在这里插入图片描述
上图可以看出时间是从16点开始,为什么呢,因为我们使用的时间跟mongodb里面的时间早了8个小时,时区不一样,统计的时候要提前8个小时统计;

2、$group 对象中有一个特点的字段就是_id ,它就是分组统计的字段集合,_id对象后面跟着的是分组统计函数统计的数据比如sum max min 等函数;
基于上面的语句我们来一个例子,根据每天进行分组统计出王小明购买金额,以及最大的一笔金额最小的一笔金额,以及产生了多少笔交易,并显示用户名称字段name;语句怎么来写?首先我还是分析一下需求;分组条件是日期精细到天类似于2019-04-01分组,首先我们获取到addtime的年月日然后进行分组统计:具体语句如下图:

在这里插入图片描述

分析一下上图写法思路。1、定义 g r o u p 然 后 定 义 分 组 字 段 i d , 确 认 i d 里 面 分 组 内 容 年 月 日 用 户 名 称 ; 分 组 定 义 完 了 后 , 后 面 跟 统 计 字 段 。 3 、 group 然后定义分组字段_id,确认_id里面分组内容年月日用户名称;分组定义完了后,后面跟统计字段。 3、 groupid,id3project 项目,表里面的项目就是字段了;所以这个对象是展示所需的字段默认是分组里面有什么就全部展示;这个很简单来看看下面的语法就ok了。
在这里插入图片描述
分析一下上面语句,分组字段_id不用写自动显示的。上面语法含义相当于 maxMoney as maxMoney_new。maxMoney_new 这个字段是自定义的。
4、$sort 这个一看就是排序功能需要的,需要排序的字段跟在后面,具体语法如下:

在这里插入图片描述

解析:排序升序是1 ,倒序是-1;上面理解为名称升序,最大金额倒序,交易次数倒序。
5、sql语句里面有个having,在mongodb怎么来实现呢,看了上面的代码其实已经很明了。在mongodb中是没有这个语法的,但是支持多次过滤的。意思就是可以在代码后面继续加$match进行filter。
如下图:
在这里插入图片描述
这个就是实现having功能,过滤出最大金额大于等于256的数据,后面还可以进行分组 过滤 排序 等等…
这里是全部代码 结尾的skip 跟limit 是分页

db.getCollection('tablename').aggregate([
  {
    $match: {
      $and: [
        {
          name: {
            $eq: ”王小明”
          }
        },
        {
          money: {
            $gte: 200,
            $lt: 300
          }
        },
        {
          addTime: {
            $gte: ISODate("2019-03-31T16:00:00Z"),
            $lt: ISODate("2019-04-11T16:00:00Z")
          }
        }
      ]
    }
  },
  {
    $group: {
      _id: {
        year: {
          $year: {
            $add: [
              "$addTime",
              28800000
            ]
          }
        },
        month: {
          $month: {
            $add: [
              "$addTime",
              28800000
            ]
          }
        },
        day: {
          $dayOfMonth: {
            $add: [
              "$addTime",
              28800000
            ]
          }
        },
        name: "$name"
      },
      maxMoney: {
        $max: "$money"
      },
      minMoney: {
        $min: "$money"
      },
      tradeCount: {
        $sum: 1
      }
    }
  },
  {
    $project: {
      maxMoney_new: '$maxMoney',
      minMoney_new: "$minMoney",
      tradeCount_new: "$tradeCount"
    }
  },
  {
    $sort: {
      name: 1,
      maxMoney: -1,
      tradeCount: -1,
      
    }
  },
  {
    $match: {
      maxMoney_new: {
        "$gte": 256
      }
    }
  },
  {
    $skip: 0
  },
  {
    $limit: 10
  }
],
{
  "allowDiskUse": true
});

总结:mongoDB的使用语句记住JSON格式以及语法层级关系,写起来得心应手,有什么疑问和探讨的欢迎在下面留言。再说一句 allowDiskUse 这个是启用磁盘缓存,防止返回数据过多报错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值