$ addToSet的替代方法来处理数组中的元素(而不是整个数组)

时间:2014-09-15 12:01:24

标签: mongodb aggregation-framework

我在MongoDB中有一个包含以下模式的文档:

{
        "_id" : {
                "id" : "ID1",
                "type" : "TYPE1"
        },
        "attrs" : [
                {
                        "name" : "ATTR1",
                        "value" : "foo"
                },
                {
                        "name" : "ATTR2",
                        "type" : "bar"
                },
                ...
                {
                        "name" : "ATTRn",
                        "value" : "blabla"
                }
        ]
}

集合中的每个文档都代表一个实体(具有唯一的ID和类型)和一组属性。每个文档可以具有多个属性,甚至属于相同类型(即具有相同_id.type的两个文档可以具有不同的属性集)。

我想获取与给定类型相关联的属性的名称(实际上,属性集的并集)。我尝试使用以下内容:

db.runCommand({aggregate: "col", pipeline: [ {$group: {_id: "$_id.type", attr: {$addToSet: "$attrs.name"}} }]})

结果是:

{
        "result" : [
                {
                        "_id" : "TYPE1",
                        "attr" : [
                                [
                                        "ATTR1",
                                        "ATTR2",
                                        "ATTR3"
                                ],
                                [
                                        "ATTR4",
                                        "ATTR5"
                                ]
                        ]
                },
                ...                    
        ],
        "ok" : 1
}

问题是$addToSet在添加数组元素时不会逐个元素地处理。而不是那样,它将整个数组视为单个元素。因此,最后得到的是一个"数组阵列"而我想拥有的是这样的:

{
        "result" : [
                {
                        "_id" : "TYPE1",
                        "attr" : [

                                    "ATTR1",
                                    "ATTR2",
                                    "ATTR3",                                 
                                    "ATTR4",
                                    "ATTR5"
                        ]
                },
                ...                    
        ],
        "ok" : 1
}

如何重新制作上述查询以获得此结果?

2 个答案:

答案 0 :(得分:3)

在分组之前,您需要$unwind attrs数组:

db.col.aggregate([
    {$unwind: '$attrs'},
    {$group: {_id: "$_id.type", attr: {$addToSet: "$attrs.name"}} }
])

输出:

{
    "result" : [ 
        {
            "_id" : "TYPE1",
            "attr" : [ 
                "ATTRn", 
                "ATTR2", 
                "ATTR1"
            ]
        }
    ],
    "ok" : 1
}

$unwind每个文档重复一次,每个attr元素一次。

答案 1 :(得分:1)

再次查看Mongo v2.4 +

$addToSet$each相结合,可以完美地保存和更新,只要它们不存在

{ $addToSet: { <field>: { $each: [ <value1>, <value2> ... ] } } }

参考:https://docs.mongodb.com/manual/reference/operator/update/each/#up._S_each