概述
1 简介
在工作的过程中,使用MongoDB存储业务数据,有时候想做的不仅仅是将数据从MongoDB中提取出来,可能需要对数据进行分析并加以利用。在党费收缴模块开发过程中,需要根据党支部名称进行分组,统计出党支部内人员的数目,每个党支部应缴党费和实缴党费的总和 等统计信息。
由于spring-data-mongodb-1.9.5.RELEASE版本太低,因此在调用mongoTemplate类型的aggregate聚合框架时,曝出如下问题
The 'cursor' option is required, except for aggregate with the explain argument
花费了较多的时间,最后选择不使用聚合框架aggregate,改用了如下函数实现了该功能
public DBObject group(DBObject key, DBObject cond, DBObject initial, String reduce) {
return this.group(key, cond, initial, reduce, (String)null);
}
2 问题描述
2.1 数据库表
// 21
{
"_id": "5283e22c98dd4158a2bf378fb394ad7b",
"_class": "DBObject",
"name": "partydues",
"cname": "党费收缴",
"map": {
"partyDues": 410,
"assigneeXM": "霍建华",
"year": "2019",
"assigneeUserID": "8ef3f163242b4059a4187f3eaf07f7e1",
"roleId": "009002",
"dataType": "task",
"assigneeUserName": "huojianhua",
"pid": "3312512",
"userId": "3e7b5e3d9b6f4c768524453115baca81",
"partyDueShouldBe": 95.06,
"cnName": "周杰伦",
"month": "01",
"createTime": "2018-11-27 16:28:41",
"roleName": "党支部1",
"taskId": "3312578",
"username": "gaochao"
}
}
// 22
{
"_id": "9513e93b58534bbb8441cca2edabef25",
"_class": "DBObject",
"name": "partydues",
"cname": "党费收缴",
"map": {
"partyDues": 711,
"assigneeXM": "宋全恒",
"year": "2019",
"assigneeUserID": "cf8d1fd5c23f4778b7c0f537d6de2c41",
"roleId": "009003",
"dataType": "task",
"assigneeUserName": "songquanheng",
"pid": "3312512",
"userId": "be2c971ee03b4a4ea2577f381329818f",
"partyDueShouldBe": 95.06,
"cnName": "沈万三",
"month": "01",
"createTime": "2018-11-27 16:29:30",
"roleName": "党支部2",
"taskId": "3312562",
"username": "shenwanshan"
}
}
// 23
{
"_id": "470e1e258b0443d2aa4b1c6b3cce5561",
"_class": "DBObject",
"name": "partydues",
"cname": "党费收缴",
"map": {
"partyDues": 100,
"assigneeXM": "宋全恒",
"year": "2019",
"assigneeUserID": "cf8d1fd5c23f4778b7c0f537d6de2c41",
"roleId": "009003",
"dataType": "task",
"assigneeUserName": "songquanheng",
"pid": "3325001",
"userId": "be2c971ee03b4a4ea2577f381329818f",
"partyDueShouldBe": 95.06,
"cnName": "周芷若",
"month": "02",
"createTime": "2018-11-27 17:09:00",
"roleName": "党支部1",
"taskId": "3325051",
"username": "zhouzhiruo"
}
}
2.2 shell命令
db.partyDues.aggregate([
$match: {“map.month”: “11”, “map.year”: “2018”, “map.dataType”: “task”}, {
“$group”: {
_id: “$map.roleName”,
“sumOfPartyDueShouldBe”: {“$sum”: “$map.partyDueShouldBe”},
“sumOfPartyDues”: {“$sum”: “$map.partyDues”},
“totalNumOfPerson”: {“$sum”: 1}}
}
])
2.3 Java源代码实现
相应的Java的源代码如下:
public JSONObject findPartyDuesByParty(String year, String month) {
String reduce = "function(doc, pre) " +
"{" +
"pre.count+=1;" +
"var partyDueShouldBe = doc.map.partyDueShouldBe;"+
"partyDueShouldBe = typeof(partyDueShouldBe)=='string'?0:partyDueShouldBe;"+
"pre.sumOfPartyDueShouldBe+=partyDueShouldBe;" +
"pre.sumOfPartyDues += doc.map.partyDues;" +
"}";
Query query = new Query();
query.addCriteria(new Criteria("map.year").is(year))
.addCriteria(new Criteria("map.month").is(month))
.addCriteria(new Criteria("map.dataType").is("task"));
DBObject result = mongoTemplate.getCollection(PARTYDUES_TABLE).group(new BasicDBObject("map.roleName", 1).append("map.roleId", 0),
query.getQueryObject(), new BasicDBObject("count", 0).append("sumOfPartyDueShouldBe", 0).append("sumOfPartyDues", 0),
reduce);
if (null == result) {
logger.info("findPartyDuesByParty cannot find partyDues Info using the reduce");
return null;
}
JSONObject ret= JSONObject.fromObject(result.toMap());
DecimalFormat df = new DecimalFormat("0.00");
JSONObject res = new JSONObject();
for (int i=0; i<ret.size(); i++) {
JSONObject ele = ret.getJSONObject(String.valueOf(i));
String key = ele.getString("map.roleName");
double sumOfPartyDueShouldBe = ele.getDouble("sumOfPartyDueShouldBe");
double sumOfPartyDues = ele.getDouble("sumOfPartyDues");
sumOfPartyDueShouldBe = Double.parseDouble(df.format(sumOfPartyDueShouldBe));
sumOfPartyDues = Double.parseDouble(df.format(sumOfPartyDues));
//获取党费收缴负责人信息
String roleId = ele.getString("map.roleId");
Map<String, String> leaderMap = null;
try {
leaderMap = userService.getPartyLeaderInfoByRoleId(roleId);
} catch (Exception e) {
e.printStackTrace();
}
if (null == leaderMap) {
logger.info("Program cannot find the leaderUserId using roleId: "+ roleId);
return null;
}
String leaderXM = leaderMap.get("XM");
String leaderPhone = leaderMap.get("PHONE");
ele.put("sumOfPartyDueShouldBe", sumOfPartyDueShouldBe);
ele.put("sumOfPartyDues", sumOfPartyDues);
ele.put("year", year);
ele.put("month", month);
ele.put("partyLeaderName", leaderXM);
ele.put("partyLeaderPhone", leaderPhone);
res.put(key, ele);
}
return res;
}
2.4 Group操作
作为使用Map-Reduce的替代方法进行数据聚合,程序员可以使用group操作,这个操作与SQL的group在查询格式上类似,因此在使用上更加方便。但使用group操作确实有一些限制,举例来说它不可使用在分享环境shared environment。并且以BSON格式返回完整的结果集,因此结果应该比较小,少于10000keys。
{ "_id" : ObjectId("4ec1d25d41421e2015da64f1"), "x" : 1 }
{ "_id" : ObjectId("4ec1d25d41421e2015da64f2"), "x" : 1 }
{ "_id" : ObjectId("4ec1d25d41421e2015da64f3"), "x" : 2 }
{ "_id" : ObjectId("4ec1d25d41421e2015da64f4"), "x" : 3 }
{ "_id" : ObjectId("4ec1d25d41421e2015da64f5"), "x" : 3 }
{ "_id" : ObjectId("4ec1d25d41421e2015da64f6"), "x" : 3 }
如果要以每行记录中的x进行分组,同时统计出每个x出现的次数。则对应的java代码如下:
GroupByResults<XObject> results =
mongoTemplate.group("group_test_collection",
GroupBy.key("x").initialDocument("{ count: 0 }").reduceFunction("function(doc, prev) { prev.count += 1 }"), XObject.class);
第一个参数为要进行聚合的集合名,第二个参数则是流式API,通过GroupBy类指定了group操作的属性。在例子中仅仅使用了initialDocument和reduceFuction方法。我们也可以指定一个key-function,以及一个finalizer作为流式 API一部分。如果你有多个keys要进行分组,则可以传递多个keys列表,以逗号分隔。
group操作的原生结果是一个JSON文档,看起来如下:
{
"retval" : [ { "x" : 1.0 , "count" : 2.0} ,
{ "x" : 2.0 , "count" : 1.0} ,
{ "x" : 3.0 , "count" : 3.0} ] ,
"count" : 6.0 ,
"keys" : 3 ,
"ok" : 1.0
}
在retval文档被映射到group方法中第三个参数,在这个情形下XObject类展示如下:
public class XObject {
private float x;
private float count;
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getCount() {
return count;
}
public void setCount(float count) {
this.count = count;
}
@Override
public String toString() {
return “XObject [x=” + x + “ count = “ + count + “]”;
}
}
也可以通过调用getRawResults在类GroupByResults类上获得原生结果成一个Document。
3 参考
https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.aggregation
4文档下载
https://download.csdn.net/download/lk142500/10815398
最后
以上就是天真小虾米为你收集整理的mongoTemplate使用group函数进行分组和统计1 简介2 问题描述3 参考4文档下载的全部内容,希望文章能够帮你解决mongoTemplate使用group函数进行分组和统计1 简介2 问题描述3 参考4文档下载所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复