如何使用聚合对Mongo集合进行分组,同时我在结果中也需要其他文件

时间:2016-11-18 13:23:33

标签: mongodb

我遇到需要从MongoDB中的集合查询结果的情况。我想使用$ group基于一个字段聚合我的集合。但我想在结果中留下那些剩余的字段,但不在这些字段上应用任何聚合函数,如($ first,$ sum等)。这些剩余的字段应该在数组中。

Example: My collection:

-------------------------------------------------------------------------
|  name  | age  | sex | province | city| area | address |
-------------------------------------------------------------------------
|   A    | 22   |  m  |  Manglr  |  p1 |  c1  |  a1 |
|   A    | 22   |  m  |  Kolkt   |  p2 |  c2  |  a2 |
|   B    | 24   |  m  |  Mumb    |  p3 |  c3  |  a3 |
|   B    | 24   |  m  |  Koch    |  p4 |  c4  |  a4 |
|   B    | 24   |  m  |  Hydrbd  |  p5 |  c5  |  a5 |
-------------------------------------------------------------------------

Result I want: ($group by 'name' field only)

[
   {
   "name" : “A”,
   "province" : [“Manglr", ‘Kolkt’]
   "city" : [“p1”, ‘p2’],
   "area" : [“c1”, ‘c2’],
   "address" : [“a1”, ‘a2’],
 },
   {
  "name" : “B”,
   "province" : [“Mumb", ‘Koch’, 'Hydrbd']
   "city" : [“p3”, ‘p4’,”p5”],
   "area" : [“c3”, ‘c4’,”c5”],
   "address" : [“a3”, ‘a4’,’a5’],
}
]

Please anyone help me to create a Mongo Query or Java code

2 个答案:

答案 0 :(得分:1)

你可以尝试这样的事情。根据需要对其他字段进行分组和推送。

aggregate([{
    "$group": {
        "_id": "$name",
        "province": {
            $push: {
                "key": "$province"
            }
        },
        "city": {
            $push: {
                "key": "$city"
            }
        },
        "area": {
            $push: {
                "key": "$area"
            }
        },
        "address": {
            $push: {
                "key": "$address"
            }
        }
    }
}, {
    "$project": {
        "_id": 0,
        "name": "$_id",
        "province": "$province.key",
        "city": "$city.key",
        "area": "$area.key",
        "address": "$address.key"
    }
}])

示例输出:

 { "province" : [ "Manglr", "kokat" ], "city" : [ "p1", "p2" ], "area" : [ "c1", "c2" ], "address" : [ "a1", "a2" ], "name" : "A" }
 { "province" : [ "Mumb", "Koch" ], "city" : [ "p3", "p4" ], "area" : [ "c3", "c4" ], "address" : [ "a3", "a4" ], "name" : "B" }

答案 1 :(得分:0)

我不知道MongoDB的方式,但以下是你可以做的Java。

package com.grs.stackOverFlow.pack05;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;


class UserAccumulated{
    private String name;
    private List<String> city;
    private List<Integer> age;
    private List<Character> sex;

    public UserAccumulated(){
        city=new ArrayList<>();
        age=new ArrayList<>();
        sex=new ArrayList<>();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getCity() {
        return city;
    }

    public void setCity(List<String> city) {
        this.city = city;
    }

    public List<Integer> getAge() {
        return age;
    }

    public void setAge(List<Integer> age) {
        this.age = age;
    }

    public List<Character> getSex() {
        return sex;
    }

    public void setSex(List<Character> sex) {
        this.sex = sex;
    }

    public void addAge(Integer age2) {
        age.add(age2);
    }

    public void addCity(String city2) {
        city.add(city2);
    }

    public void addSex(Character sex2) {
        sex.add(sex2);
    }


    public String toString(){
        return String.format("{name:%s,cities : %s, sex: %s, age: %s}", name,city,sex,age);
    }

}

public class User {
    private String name,city;
    private Integer age;
    private Character sex;


    public User(String name, String city,  Integer age, Character sex) {
        super();
        this.name = name;
        this.city = city;
        this.age = age;
        this.sex = sex;
    }

    public static void main(String...args){
        //create a sample list ..you have to replace with code to retrieve data from mongo db
        List<User> rows = Arrays.asList(new User("A", "Manglr", 22, 'm'),
                      new User("A", "Manglr", 22, 'm'),
                      new User("B", "addad",  22, 'm'),
                      new User("C", "addsadad",  22, 'm'),
                      new User("C", "sadd", 21, 'm'));


        //aggregating
        List<UserAccumulated> result=new ArrayList<>();
        //parallestream if many records else use stream
        Map<String, List<User>> map = rows.parallelStream().collect(Collectors.groupingBy(User::getName));

        for(Entry<String, List<User>> entry: map.entrySet()){
            UserAccumulated userA=new UserAccumulated();
            userA.setName(entry.getKey());
            for(User user : entry.getValue()){
                userA.addAge(user.getAge());
                userA.addCity(user.getCity());
                userA.addSex(user.getSex());
            }
            result.add(userA);
        }


        for(UserAccumulated a: result)
            System.out.println(a);

    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Character getSex() {
        return sex;
    }
    public void setSex(Character sex) {
        this.sex = sex;
    }

}

输出如下:

{ name: A,cities : [Manglr, Manglr], sex: [m, m], age: [22, 22]} {name:B,cities : [addad], sex: [m], age: [22]} {name:C,cities : [addsadad, sadd], sex: [m, m], age: [22, 21]}

我没有把你的所有专栏用来保持简单。我不确定它与您的实际数据量的运行速度有多快。但如果性能问题让我知道。