MongoDB分组汇总操作,及Spring data mongo的实现

时间:2023-03-08 17:29:27
MongoDB分组汇总操作,及Spring data mongo的实现

转载请在页首注明作者与出处

一:分组汇总

1.1:SQL样例

分组汇总的应用场景非常多,比如查询每个班级的总分是多少,如果用关系形数据库,那么sql是这样子的

SELECT count(1),class from score group by class

得到的结果就是每个班分别的总分是多少,那么在mongodb这种非关系数据库要怎么做呢?

1.2:数据样例

假如我们有如下数据若干

{
"_id" : "4fe31003-0ee3-47b8-8a1d-0e9f8561c37e",
"systemId" : "test",
"bizId" : "test",
"channel" : "通道一",
"msg" : "你好!",
"createTime" : ISODate("2016-10-25T09:17:12.228+0000"),
"useTime" : NumberLong(274),
"success" : NumberInt(1)
}
{
"_id" : "4fe31003-0ee3-47b8-8a1d-0e9f8561c37e",
"systemId" : "test",
"bizId" : "test",
"channel" : "通道二",
"msg" : "你好!",
"createTime" : ISODate("2016-10-25T09:17:12.228+0000"),
"useTime" : NumberLong(274),
"success" : NumberInt(1)
}
 

1.3:需求

如上短信的发送记录,我们可能统计不同短信通道channnel的发送数量。

1.4:mongodb查询语法

db.shortMessageLog.aggregate([{$group : {_id : "$channel" , num : {$sum : 1}}}]);

这意味着对channel进行分组,并且查询出来的分组名称以id的形式显示出来

查询结果如下:

{
"_id" : "通道一",
"num" : NumberInt(12504)
}
{
"_id" : "通道二",
"num" : NumberInt(594)
}

1.5:汇总时加入查询条件

这又是一个新的需求,我们可能只想统计一定时间的内的数量,所以我们需要加入查询条件。

新的语句如下

db.shortMessageLog.aggregate([{$match:{createTime:{$gte:new Date(2016,9,28)}}},{$group : {_id : "$channel" , num : {$sum : 1}}}]);

这里使用$match来匹配指定时间的数量。

小提示:mongodb的月份是从0开始的,也就是上面参数中的9,其实代码的是10月份。

我这里匹配时间大于2016-10-28号以后的数据,然后再交给后面的条件去分组。

1.6:使用java代码的实现

我们这里使用spring data mongo,相比原生的mongo驱动,这个确实要好用很多。

实现的需求就是根据时间来分组统计数量

        Aggregation agg = null;
Criteria createTime = Criteria.where("createTime");
boolean timeTag = false;
if(startTime != null){
createTime.gte(startTime);
timeTag = true;
}
if(endTime != null){
createTime.lte(endTime);
timeTag = true;
}
GroupOperation groupOperation = Aggregation.group("channel").count().as("count");
if(timeTag){
agg = Aggregation.newAggregation(ShortMessageLog.class,Aggregation.match(createTime),groupOperation);
}else{
agg = Aggregation.newAggregation(ShortMessageLog.class, groupOperation);
}
AggregationResults<Map> results = mongoTemplate.aggregate(agg,ShortMessageLog.class,Map.class);