按数组对文档进行分组,将数组视为一组

时间:2016-03-25 03:56:34

标签: mongodb mongodb-query aggregation-framework

我有一个相当简单的任务我想使用MongoDB的聚合管道来实现。我想将一个字段中的数组视为集合(即忽略顺序和重复),并按它们分组。例如,集合可能是:

[
    {
        _id: 1
        names: ["a", "b"]
    },
    {
        _id: 2
        names: ["c", "a"]
    },
    {
        _id: 3
        names: ["b", "a"]
    }
]

我想要的结果是:

[
    {
        names: ["a", "b"],
        count: 2
    },
    {
        names: ["a", "c"],
        count: 1
    }
]

谢谢!

2 个答案:

答案 0 :(得分:1)

您需要$sort结果才能使其与分组键保持一致。真的没有别的办法:

db.collection.aggregate([
    { "$unwind": "$names" },
    { "$sort": { "_id": 1, "names": 1} },
    { "$group": {
        "_id": "$_id",
        "names": { "$push": "$names" }
    }},
    { "$group": {
        "_id": "$names",
        "count": { "$sum": 1 }
    }}
])

就像你问的那样回报:

[
    {
        "_id": ["a", "b"],
        "count": 2
    },
    {
        "_id": ["a", "c"],
        "count": 1
    }
]

虽然有很多运算符像“集合”那样处理数组,但是没有一个运算符将数组内容“重新排序”为一种在分组时应用的一致方式。只有在$sort时才会这样做。

即使数组包含“重复”,并且应用了一些设置转换,它们仍然没有按顺序排列:

db.testa.insert_many([
    { "a" : [ "a", "b" ] },
    { "a" : [ "b", "a" ] },
    { "a" : [ "b", "a", "a" ] }
])

db.testa.aggregate({ "$project": { "_id": 0, "a": { "$setUnion": [ "$a", [] ] } } })

该样本当然会返回:

{ "a" : [ "b", "a" ] }
{ "a" : [ "a", "b" ] }
{ "a" : [ "a", "b" ] }

因此,您仍然需要$unwind$sort才能获得用于分组目的的一致“设置”。

答案 1 :(得分:1)

您可以通过将多个聚合管道拼接在一起来获得结果。

db.collection.aggregate([
 {$unwind:"$names"},
 {$sort:{_id:1, names:1}},
 {$group:{_id:"$_id", names:{$push:"$names"}}},
 {$group:{_id:"$names", count:{$sum:1}}},
 {$project:{_id:0, names:"$_id", count:1}}
])

它发出:

{ 
    "count" : NumberInt(1), 
    "names" : [
        "a", 
        "c"
    ]
}
{ 
    "count" : NumberInt(2), 
    "names" : [
        "a", 
        "b"
    ]
}