spring boot mongodb 统计表中某一字段的所有值,其中aggregate的用法之一

pom.xml 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

yml文件配置:

data:
  mongodb:
    port: 27017
    host: xx.xx.xx.xx//(IP地址)
    database: test

这里因为用nosql,非关系型数据库,所以只说明非实体类统计的用法,即,数据库中的表没有对应的实体类;

需求是:统计表中某列的总和

代码:

public Long getSumByScoreField(String name, String subject, String time) {
        DBCollection collection = mongoTemplate.getCollection("user");//user为表
        String matchStr = "{\"$match\":{\"name\":\"" + name+ "\",\"subject\":\"" + subject+ "\",\"login_time\":\"" + time + "\"}}";
        String groupStr = "{\"$group\":{\"_id\": null,\"total\":{\"$sum\": \"$score\"}}}";
        System.out.println(JSON.parse(matchStr));
        DBObject match = (DBObject) JSON.parse(matchStr);
        DBObject group = (DBObject) JSON.parse(groupStr);
        LinkedList<DBObject> list= new LinkedList<>();
        objects.add(match);
        objects.add(group);
        Cursor cursor = collection.aggregate(list, AggregationOptions.builder().outputMode(AggregationOptions.OutputMode.CURSOR).build());
        while (cursor.hasNext()){
            System.out.println(cursor.next());
        }
}

以上代码中如果是第一次接触的同行就有一些陌生的关键字,如:$match,$group,$sum,这三个皆为对应mongodb的关键字,

match是依据的条件查询,group是分组查询,在该需求就会用到,sum聚合函数求总和,还有一个$score,这个是表中的字段score,因为要求和的正是该字段的和,固定写法而已,至于其他字段都是表的字段,注意这里没有对应的POJO类。

上述的代码中有这么一段代码:

Cursor cursor = collection.aggregate(list, AggregationOptions.builder().outputMode(AggregationOptions.OutputMode.CURSOR).build());

需要额外说明一下,这段代码之前我是这么写的:

AggregationOutput aggregate2 = collection.aggregate(match, group);

或者是:

AggregationOutput aggregate2 = collection.aggregate(list);

这么写的,很多时候在执行到这段代码的时候会出错,所以就改成上述代码段里的写法了因为当写成上面红色代码的两种方式时会报错:

com.mongodb.MongoCommandException: Command failed with error 9: 'The 'cursor' option is required, except for aggregate with the explain argument' on server 192.168.31.14:27017. The full response is { "ok" : 0.0, "errmsg" : "The 'cursor' option is required, except for aggregate with the explain argument", "code" : 9, "codeName" : "FailedToParse" }
    at com.mongodb.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:115) ~[mongodb-driver-core-3.4.3.jar:na]

这种报错要么是依赖的mongodb版本和spring-bootstart版本不同,要么就是:这里细心的同行会发现,错误的(标红字)和正确的(代码段里面的)返回值类型不同,Cursor为输入模型的,AggregationOutput 为输出模型的,默认是输出模型,所以,当出现上述异常时可以改下代码为输入模型即可;

上述代码段还可以有一下写法:

  public Long getSumByScoreField(String name, String subject, String time) {
    BasicDBObject basicDBObject = new BasicDBObject();
//        basicDBObject.put("name", name);
//        basicDBObject.put("subject", subject);
//        basicDBObject.put("update_time", time);
        BasicDBObject[] basicDBObjects = {new BasicDBObject("name", name), new BasicDBObject("subject", subject), new BasicDBObject("update_time", time)};
//        BasicDBObject basicDBObject = new BasicDBObject();
        basicDBObject.put("$and", basicDBObjects);
        BasicDBObject smatch = new BasicDBObject();
        smatch.put("$match", basicDBObject);
        BasicDBObject dbObject = new BasicDBObject("_id", null);
        dbObject.put("total", new BasicDBObject("$sum", "$score"));
//        DBObject group = new BasicDBObject("$group", dbObject);
        List list = new LinkedList();
        list.add(smatch);
        list.add(group);
        Cursor aggregate = collection.aggregate(list, AggregationOptions.builder().outputMode(AggregationOptions.OutputMode.CURSOR).build());
        if (aggregate.hasNext()) {
            System.out.println(aggregate.next().get("total"));
        }
}

以上的两种写法最终翻译成mysql查询代码为:

select sum(score) as total from user where name=? and subject = ?and time=?

mongodb的写法为:

db.user.aggregate()
    .match({"name":"JONE","subject":"数学","update_time":"2019-01-02"}).group({
          _id: null,total:{$sum: "$score"}
    })

如果是关系型,也就是创建对应表的实体类POJO的话就用:(这段代码还没测试,但大概思路、用法是这样的)

Aggregation aggregation = Aggregation.newAggregation(
                match(Criteria.where("name").is(name).and("subject").is(subject).and("update_time").is(time)),
                group("_id").sum("score").as("total"),
                sort(Sort.Direction.DESC, "total"),
                limit(1));
        mongoTemplate.aggregate(aggregation,User.class,BasicDBObject.class);

补充--分组统计:

需求点:分组查询出选择不同班级,不同学科,不同时间报名中每组的总人数及总成绩

mysql:SELECT subject,DATE_FORMAT(sign_up_time,'%Y-%m-%d'),class_name,SUM(users_quantum) AS users_quantum,SUM(score)AS score FROM user
GROUP BY  class_name,DATE_FORMAT(sign_up_time,'%Y-%m-%d'),subject

mongodb:aggregate([{$group: { _id: {class_name:"$class_name",subject:"$subject",sign_up_time:"$sign_up_time"},total:{$sum: "$score"},count:{$sum:1}}}])

注意:mongodb sql中双引号里面的自定义字段(除数据库聚合函数,即sql关键字之外的字段)必须加$符号

字段说明:subject-学科,class_name-班级名称,sign_up_time-报名时间,users_quantum-报名人数,score-成绩

以上纯属个人的一点开发实际来历,希望可以帮到见到的你,如有好的想法、方法。

请留言,谢谢!

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

焱墩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值