springboot mongodb 实现分组查询操作

如何在spring boot中使用mongodb实现group这样的分组统计查询呢?
比如:统计中国每个省的同名人数,数据内容如下:

{ "country" : "china", "province" : "sh", "userid" : "a" }  
{  "country" : "china", "province" : "sh", "userid" : "b" } 
{  "country" : "china", "province" : "sh", "userid" : "c" }  
{  "country" : "china", "province" : "bj", "userid" : "da" }  
{  "country" : "china", "province" : "bj", "userid" : "fa" }  

统计结果为:[{"country" : "china", "province" : "sh", "count" : 3 },{"country" : "china", "province" : "bj", "count" : 2 }]
使用aggregate([{ $group: {"_id": { "country" : "$country", "province": "$province" , "uid" : "$userid" } } } , { $group: {"_id": { "country" : "$_id.country", "province": "$_id.province" }, count : { $sum : 1 } } }]) mongdb正确获取到数据,那怎么使用java 在springboot中实现呢?

阅读 14.2k
2 个回答

使用聚合查询aggregation实现。由于mongodb数据库的特点,聚合使用到了管道操作。(PS. group 操作不能返回指定字段以外的其他字段)
类似的实现如下几步:

Aggregation agg = Aggregation.newAggregation(
                // 第一步:挑选所需的字段,类似select *,*所代表的字段内容
                Aggregation.project("licensePlate", "companyName", "deviceCode", "diverName", "fleet", "lineNumber",
                        "imgUrl", "videoUrl", "ptLoc", "locations"), 
                // 第二步:sql where 语句筛选符合条件的记录
                Aggregation.match(
                        Criteria.where("companyName").is(companyName).and("addedDate").gte(startTime).lte(endTime)), 
                // 第三步:分组条件,设置分组字段
                Aggregation.group("companyName", "licensePlate")
                        .count().as("allCount")// 增加COUNT为分组后输出的字段
                        .last("deviceCode").as("deviceCode").last("diverName").as("diverName").last("fleet").as("fleet")
                        .last("lineNumber").as("lineNumber").last("imgUrl").as("imgUrl").last("videoUrl").as("videoUrl")
                        .last("ptLoc").as("ptLoc").last("locations").as("locations"), // 增加publishDate为分组后输出的字段
                // 第四步:重新挑选字段
                Aggregation.project("diverName", "licensePlate", "companyName", "deviceCode", "allCount", "fleet",
                        "lineNumber", "imgUrl", "videoUrl", "ptLoc", "locations")
        );
        AggregationResults<HeatMap> results = mongoOperations.aggregate(agg, "Historys", HeatMap.class);
        List<HeatMap> list = results.getMappedResults();

管道执行的性质,每一步按顺序执行,第一步操作结果传递给下一步进行才做,所以代码的顺序影响最后的结果,因此要想分组后获取集合其他字段,第一步和最后一步都要指定一下想要返回的字段。

图片描述


    class User {
        private String country;
        private String province;
        private String name;

        public User(String country, String province, String name) {
            this.country = country;
            this.province = province;
            this.name = name;
        }

        public String getCountry() {
            return country;
        }

        public void setCountry(String country) {
            this.country = country;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
    class Res {
        private String country;
        private String province;
        private Integer count;

        public Res(String country, String province, Integer count) {
            this.country = country;
            this.province = province;
            this.count = count;
        }

        public String getCountry() {
            return country;
        }

        public void setCountry(String country) {
            this.country = country;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public Integer getCount() {
            return count;
        }

        public void setCount(Integer count) {
            this.count = count;
        }
    }

    @Test
    public void test1() throws Exception {
        List<Res> result = new ArrayList<>();

        List<User> list = new ArrayList<>();
        list.add(new User("中国", "北京", "张三"));
        list.add(new User("中国", "北京", "张三"));
        list.add(new User("中国", "北京", "李四"));
        list.add(new User("中国", "北京", "李四"));
        list.add(new User("中国", "北京", "李四"));
        list.add(new User("中国", "北京", "王五"));
        list.add(new User("中国", "湖南", "张三"));
        list.add(new User("中国", "湖南", "张三"));
        list.add(new User("中国", "湖南", "张三"));

        list.stream()
                .collect(Collectors.groupingBy(e -> e.getProvince()))
                .forEach((k, v) -> {
                    StringBuilder count = new StringBuilder("0");
                    v.stream().
                            collect(Collectors.groupingBy(e -> e.getName()))
                            .forEach((k2, v2) -> {
                                if (v2.size() > 1) {
                                    int c = Integer.parseInt(count.toString());
                                    count.delete(0, count.length());
                                    count.append(c + v2.size());
                                }
                            });
                    result.add(new Res(v.get(0).getCountry(), v.get(0).getProvince(), Integer.parseInt(count.toString())));
                    count.delete(0, count.length());
                });
        System.out.println(new ObjectMapper().writeValueAsString(result));
    }

StringBuilder只是起了一个计数的作用, 虽然有点low~

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题