Spring Data MongoDB 使用group和unwind实现对数组数据进行简单统计

来源:互联网 发布:java开发笔试题及答案 编辑:程序博客网 时间:2024/05/24 07:40

Spring Data MongoDB 使用group和unwind实现对数组数据进行简单统计

先简单交代一下需求:新高考政策下,高中学生可以组合选择自己喜欢的三门副科,选科结束后教务需要看到这次选科的单科统计信息。数据库中保存的数据结构如下:

{    "_id" : ObjectId("599bc8be5ae9fb99b2ca2499"),    "_class" : "com.xxx.db.model.SelectCourseRecord",    "selectCourse" : "599bc8be5ae9fb99b2ca2498",    "student" : "5993b03f8a4f1a5ba4e05d08",    "courses" : [         "地理",         "物理",         "政治"    ],    "removed" : false,    "status" : "success",    "createdTime" : NumberLong(1503381694777)},{    "_id" : ObjectId("599bc8be5ae9fb99b2ca249a"),    "_class" : "com.xxx.db.model.SelectCourseRecord",    "selectCourse" : "599bc8be5ae9fb99b2ca2498",    "student" : "599a8faf8a4f1a26dcfef389",    "courses" : [         "化学",         "物理",         "政治"    ],    "removed" : false,    "status" : "success",    "createdTime" : NumberLong(1503381694795)}

也就是我们要得到选了物理、地理、化学和政治的各有多少人,如果科目不是放在数组里面的,那很简单,直接用group就可以得到结果了。如果直接对coursesgroup,你可能会得到一个莫名其妙的结果!针对这种情况,MongoDB为我们准备了unwind方法。unwind方法会将数组解开,比如上面的第一个数据,如果对其unwind的话,可以理解为我们会得到下面这样的结果:

{    "_id" : ObjectId("599bc8be5ae9fb99b2ca2499"),    "_class" : "com.xxx.db.model.SelectCourseRecord",    "selectCourse" : "599bc8be5ae9fb99b2ca2498",    "student" : "5993b03f8a4f1a5ba4e05d08",    "courses" : "地理",    "removed" : false,    "status" : "success",    "createdTime" : NumberLong(1503381694777)},{    "_id" : ObjectId("599bc8be5ae9fb99b2ca2499"),    "_class" : "com.xxx.db.model.SelectCourseRecord",    "selectCourse" : "599bc8be5ae9fb99b2ca2498",    "student" : "5993b03f8a4f1a5ba4e05d08",    "courses" : "物理",    "removed" : false,    "status" : "success",    "createdTime" : NumberLong(1503381694777)},{    "_id" : ObjectId("599bc8be5ae9fb99b2ca2499"),    "_class" : "com.xxx.db.model.SelectCourseRecord",    "selectCourse" : "599bc8be5ae9fb99b2ca2498",    "student" : "5993b03f8a4f1a5ba4e05d08",    "courses" : "政治",    "removed" : false,    "status" : "success",    "createdTime" : NumberLong(1503381694777)}

注意看,除了courses这一项不一样,其他的值都是一样的!那么此时我们再来对courses进行group的话就可以了。完整的Java代码如下:

@Servicepublic class DefaultSelectCourseRecordService extends AbstractService implements ISelectCourseRecordService {    @Override    public Map<String, Long> countSubjectSelected(String selectCourseId) {        Aggregation agg = Aggregation.newAggregation(                Aggregation.match(Criteria.where("selectCourse").is(selectCourseId)),                Aggregation.project("courses"),                Aggregation.unwind("courses"),                Aggregation.group("courses").count().as("count"),                Aggregation.project("count").and("courses").previousOperation(),                Aggregation.sort(Sort.Direction.DESC, "count")                );        AggregationResults<SubjectCount> groupResults = mongoTemplate.aggregate(agg, SelectCourseRecord.class, SubjectCount.class);        List<SubjectCount> subjectCounts = groupResults.getMappedResults();        Map<String, Long> subjectCountMap = subjectCounts.stream().collect(Collectors.toMap(t -> t.getCourses(), t -> t.getCount()));        return subjectCountMap;    }    private class SubjectCount {        private String courses;        private long count;        public String getCourses() {            return courses;        }        @SuppressWarnings("unused")        public void setCourses(String courses) {            this.courses = courses;        }        public long getCount() {            return count;        }        @SuppressWarnings("unused")        public void setCount(long count) {            this.count = count;        }    }}

聚合操作返回结果是SubjectCountList,用了Java8 Stream转为了方便一点的Map,这里的返回结果格式如下:

{    "政治": 10,    "物理": 10,    "生物": 9,    "历史": 9,    "化学": 10,    "地理": 9}

参考文档: https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/

阅读全文
1 0
原创粉丝点击