有很多时候大量日志类流水的数据存储到mongodb或者elasticsearch中,既然是数据肯定要去分析统计出我们需要的数据才是有用的数据,不然跟咸鱼没有什么区别。下面来讲讲如何运用mongodb的聚合函数(aggregate)完成sql语句中group by常规数据统计,以及常规数据查询。
MongoDB中聚合(aggregate)主要用于统计数据(比如统计平均值(sum) ,最大最小(max)等分组函数),并view计算后的统计结果。由于方便学习下面语句中省略的表达式我都写出来。
aggregate() 方法的使用
如何应用这个方法,首先我们还得了解方法的主要层级关系,我列出了一个图如下:
1、match 条件关系定义一个and(或条件可以用$or)后面跟三个条件( name,addTime, money) 组成的数组。具体语句如下图:
上图可以看出时间是从16点开始,为什么呢,因为我们使用的时间跟mongodb里面的时间早了8个小时,时区不一样,统计的时候要提前8个小时统计;
2、$group 对象中有一个特点的字段就是_id ,它就是分组统计的字段集合,_id对象后面跟着的是分组统计函数统计的数据比如sum max min 等函数;
基于上面的语句我们来一个例子,根据每天进行分组统计出王小明购买金额,以及最大的一笔金额最小的一笔金额,以及产生了多少笔交易,并显示用户名称字段name;语句怎么来写?首先我还是分析一下需求;分组条件是日期精细到天类似于2019-04-01分组,首先我们获取到addtime的年月日然后进行分组统计:具体语句如下图:
分析一下上图写法思路。1、定义project 项目,表里面的项目就是字段了;所以这个对象是展示所需的字段默认是分组里面有什么就全部展示;这个很简单来看看下面的语法就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 这个是启用磁盘缓存,防止返回数据过多报错。