MongoTemplate 聚合操作

第一部分

在写具体的业务之前我们先说明一下文档定义:

PT

@Document(collection = "pt")
public class PT implements Serializable {

    @Id
    private String id;

    /**学生id **/
    private String student_Id;

    /** 学生姓名 **/
    private String student_name;

    /** 学校id **/
    private String school_id;

    /** 学校名称 **/
    private String school_name;

    /** 年级id **/
    private String grade_id;

    /** 年级名称 **/
    private String grade_name;

    /** 班级id **/
    private String class_id;

    /** 班级名称 **/
    private String class_name;

    /** 批次 **/
    private String batch;

    /** 测试时间 **/
    private Date test_time;

    /** 项目 **/
    private List items;


Item:

public class Item implements Serializable{

    /** 项目名称 **/
    private String item_name;

    /** 分数 **/
    private double score;

    /** 单位 **/
    private String unit;

存储到mongodb中的样子:

MongoTemplate 聚合操作_第1张图片


第二部分

根据以上的文档我们经常会遇到几种需求:

Q1.统计各个年级人数

Q2.统计某个年级某一项测试在某个范围的人数

Q3..统计某个年级某一项测试不在某个范围的人数

Q4.统计各个测试项目得分的最大值,最小值,平均值

Q5.统计各个年级每一个项目得分的最大值,最小值,平均值


第三部分

针对以上集中需求,我们简单分析一下,然后用代码实现:

Q1:"统计各个年级人数"   这个比较简单,我们只需要按照年级分组然后进行sum就能得到结果

mongo :

db.pt.aggregate([ { "$group" : { "_id" : "$grade_name" , "总人数" : { "$sum" : 1}}}] )

结果:

MongoTemplate 聚合操作_第2张图片

JAVA(mongoTemplate):

Aggregation aggregation1 = Aggregation.newAggregation(Aggregation.group("grade_name").count().as("总人数"));
AggregationResults outputTypeCount1 =
        mongoTemplate.aggregate(aggregation1, "pt", BasicDBObject.class);

for (Iterator iterator = outputTypeCount1.iterator(); iterator.hasNext(); ) {
    DBObject obj = iterator.next();
    System.out.println(JSON.toJSONString(obj));
}

console:



Q2:"统计某个年级某一项测试在某个范围的人数"  这个也不难,只需要匹配 年级+测试项目+项目分数 between 分数1 and 分数2 然后根据年级分组统计

mongo :

db.pt.aggregate(
        [ { "$match" : { "grade_name" : "一年级"}} , { "$unwind" : "$items"} , { "$match" : { "items.item_name" : "BMI" , "items.score" : { "$gt" : 60 , "$lt" : 70}}} , { "$group" : { "_id" : "$grade_name" , "一年级BMI正常人数" : { "$sum" : 1}}}]
)

结果:


JAVA(mongoTemplate):

Aggregation aggregation4 =
        Aggregation.newAggregation(
                Aggregation.unwind("items"),
                Aggregation.match(Criteria.where("items.item_name").is("BMI").and("items.score").gt(60).lt(70)),
                Aggregation.group("grade_name").count().as("BMI正常人数"));
AggregationResults outputTypeCount4 =
        mongoTemplate.aggregate(aggregation4, "pt", BasicDBObject.class);

for (Iterator iterator = outputTypeCount4.iterator(); iterator.hasNext(); ) {
    DBObject obj = iterator.next();
    System.out.println(JSON.toJSONString(obj));
}

console:


Q3:"统计某个年级某一项测试不在某个范围的人数"  这个和Q2的区别在于他是not between and,这我们需要使用or来出来,java中对应的是orOperator;

mongo :

db.pt.aggregate(
        [ { "$match" : { "grade_name" : "一年级"}} , { "$unwind" : "$items"} , { "$match" : { "items.item_name" : "BMI" , "$or" : [ { "items.score" : { "$lte" : 60}} , { "items.score" : { "$gte" : 70}}]}} , { "$group" : { "_id" : "$grade_name" , "BMI不正常人数" : { "$sum" : 1}}}]
)

结果:


JAVA(mongoTemplate):

Aggregation aggregation3 =
        Aggregation.newAggregation(
                Aggregation.match(Criteria.where("grade_name").is("一年级")),
                Aggregation.unwind("items"),
                Aggregation.match(Criteria.where("items.item_name").is("BMI").orOperator(
                        Criteria.where("items.score").lte(60),
                        Criteria.where("items.score").gte(70))),
                Aggregation.group("grade_name").count().as("BMI不正常人数"));
AggregationResults outputTypeCount3 =
        mongoTemplate.aggregate(aggregation3, "pt", BasicDBObject.class);

for (Iterator iterator = outputTypeCount3.iterator(); iterator.hasNext(); ) {
    DBObject obj = iterator.next();
    System.out.println(JSON.toJSONString(obj));
}


这里有个问题需要注意:当定义多个Criteria (criteria1,criteria2,criteria3,criteria4)然后使用orOperator拼接的时候结果是不正确的,我实验然后错误的写法有两种:

1. criteria1.orOperator(criteria2) //criteria1 criteria2 是并列条件满足任一即可的【这个写法是铁定错误的!!!

2. new Criteria().orOperator(criteria1,criteria2)//criteria1 criteria2 是并列条件满足任一即可的【这个写法百度说是正确写法,不知道为什么结果和上面的是一样的

console:



Q4.“统计各个测试项目得分的最大值,最小值,平均值” 这个问题其实就是针对测试项目进行分组,然后使用 min max avg函数

mongo :

db.pt.aggregate(
        [ { "$match" : { "grade_name" : "一年级"}} , { "$unwind" : "$items"} , { "$group" : { "_id" : "$items.item_name" , "平均分" : { "$avg" : "$items.score"} , "最小值" : { "$min" : "$items.score"} , "最大值" : { "$max" : "$items.score"}}}]
)

结果:

MongoTemplate 聚合操作_第3张图片

JAVA(mongoTemplate):

Aggregation aggregation5 =
        Aggregation.newAggregation(
                Aggregation.match(Criteria.where("grade_name").is("一年级")),
                Aggregation.unwind("items"),
                Aggregation.group("$items.item_name").avg("$items.score").as("平均分").min("$items.score").as
                        ("最小值").max("$items.score").as("最大值"));
AggregationResults outputTypeCount5 =
        mongoTemplate.aggregate(aggregation5, "pt", BasicDBObject.class);

for (Iterator iterator = outputTypeCount5.iterator(); iterator.hasNext(); ) {
    DBObject obj = iterator.next();
    System.out.println(JSON.toJSONString(obj));
}


使用原生语句的写法:

//展开数组
DBObject queryUnwind=new BasicDBObject("$unwind","$items");
//分组统计
DBObject groupObject=new BasicDBObject("_id",new BasicDBObject("item_name", "$items.item_name"));
groupObject.put("min", new BasicDBObject("$min","$items.score"));
groupObject.put("max", new BasicDBObject("$max","$items.score"));
groupObject.put("avg", new BasicDBObject("$avg","$items.score"));
DBObject  queryGroup=new BasicDBObject("$group",groupObject);

AggregationOutput output=mongoTemplate.getCollection("pt").aggregate(queryUnwind,queryGroup);
for (Iterator iterator = output.results().iterator(); iterator.hasNext();) {
    DBObject obj =iterator.next();
    System.out.println(obj.toString());
}

console:


Q5.“统计各个年级每一个项目得分的最大值,最小值,平均值” 这个问题需要我们按照年级和项目名分组 计算出每一个的最大值,最小值,平均值然后把每个年级的push到一起

这里我直接使用类似原生语句的写法,不在单独写出mongo语句怎么写。

JAVA(mongoTemplate):

/* 创建 $unwind 操作, 用于切分数组*/
DBObject unwind = new BasicDBObject("$unwind", "$items");

/* Group操作*/
DBObject groupFields = new BasicDBObject("_id",new BasicDBObject("grade_name", "$grade_name").append("item_name", "$items.item_name"));
groupFields.put("min_score", new BasicDBObject("$min","$items.score"));
groupFields.put("max_score", new BasicDBObject("$max","$items.score"));
groupFields.put("avg_score", new BasicDBObject("$avg","$items.score"));
DBObject group = new BasicDBObject("$group", groupFields);

/* Reshape Group Result*/
DBObject projectFields = new BasicDBObject();
projectFields.put("grade_name", "$_id.grade_name");
DBObject subProjects=new BasicDBObject("item_name","$_id.item_name");
subProjects.put("min","$min_score");
subProjects.put("max","$max_score");
subProjects.put("avg","$avg_score");
projectFields.put("item_info",subProjects );
DBObject project = new BasicDBObject("$project", projectFields);

/* 将结果push到一起*/
DBObject groupAgainFields = new BasicDBObject("_id", "$grade_name");
groupAgainFields.put("item_info", new BasicDBObject("$push", "$item_info"));
DBObject reshapeGroup = new BasicDBObject("$group", groupAgainFields);

/* 查看Group结果 */
AggregationOutput output1 = mongoTemplate.getCollection("pt").aggregate(unwind, group, project, reshapeGroup);
for (Iterator iterator = output1.results().iterator(); iterator.hasNext();) {
    DBObject obj =iterator.next();
    System.out.println(obj.toString());
}

console:



你可能感兴趣的:(mongodb)