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);