鍍金池/ 問(wèn)答/Java  數(shù)據(jù)庫(kù)/ springboot mongodb 實(shí)現(xiàn)分組查詢操作

springboot mongodb 實(shí)現(xiàn)分組查詢操作

如何在spring boot中使用mongodb實(shí)現(xiàn)group這樣的分組統(tǒng)計(jì)查詢呢?
比如:統(tǒng)計(jì)中國(guó)每個(gè)省的同名人數(shù),數(shù)據(jù)內(nèi)容如下:

{ "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" }  

統(tǒng)計(jì)結(jié)果為:[{"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正確獲取到數(shù)據(jù),那怎么使用java 在springboot中實(shí)現(xiàn)呢?

回答
編輯回答
有點(diǎn)壞

圖片描述


    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("中國(guó)", "北京", "張三"));
        list.add(new User("中國(guó)", "北京", "張三"));
        list.add(new User("中國(guó)", "北京", "李四"));
        list.add(new User("中國(guó)", "北京", "李四"));
        list.add(new User("中國(guó)", "北京", "李四"));
        list.add(new User("中國(guó)", "北京", "王五"));
        list.add(new User("中國(guó)", "湖南", "張三"));
        list.add(new User("中國(guó)", "湖南", "張三"));
        list.add(new User("中國(guó)", "湖南", "張三"));

        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只是起了一個(gè)計(jì)數(shù)的作用, 雖然有點(diǎn)low~

2017年5月9日 05:07
編輯回答
放開(kāi)她

使用聚合查詢aggregation實(shí)現(xiàn)。由于mongodb數(shù)據(jù)庫(kù)的特點(diǎn),聚合使用到了管道操作。(PS. group 操作不能返回指定字段以外的其他字段)
類似的實(shí)現(xiàn)如下幾步:

Aggregation agg = Aggregation.newAggregation(
                // 第一步:挑選所需的字段,類似select *,*所代表的字段內(nèi)容
                Aggregation.project("licensePlate", "companyName", "deviceCode", "diverName", "fleet", "lineNumber",
                        "imgUrl", "videoUrl", "ptLoc", "locations"), 
                // 第二步:sql where 語(yǔ)句篩選符合條件的記錄
                Aggregation.match(
                        Criteria.where("companyName").is(companyName).and("addedDate").gte(startTime).lte(endTime)), 
                // 第三步:分組條件,設(shè)置分組字段
                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();

管道執(zhí)行的性質(zhì),每一步按順序執(zhí)行,第一步操作結(jié)果傳遞給下一步進(jìn)行才做,所以代碼的順序影響最后的結(jié)果,因此要想分組后獲取集合其他字段,第一步和最后一步都要指定一下想要返回的字段。

2017年4月5日 04:29