有很多时候大量日志类流水的数据存储到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)。定义一个
match对象就是sql中的where条件比如查询名字为王小明,在本月购买金额在200−300之间的数据,这个语句怎么来写,首先我们来分析一下里面有三组条件(名字name,时间addTime,金额money),条件关系是(与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、
group然后定义分组字段id,确认id里面分组内容年月日用户名称;分组定义完了后,后面跟统计字段。3、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 这个是启用磁盘缓存,防止返回数据过多报错。