具有条件的不同数组元素

时间:2016-09-01 02:16:56

标签: mongodb mongodb-query aggregation-framework

我的文件如下:

{
    "_id": "1",
    "tags": [ 
        { "code": "01-01", "type": "machine" },
        { "code": "04-06", "type": "gearbox" },
        { "code": "07-01", "type": "machine" } 
    ]
},
{
    "_id": "2",
    "tags": [
        { "code": "03-04","type": "gearbox" },
        { "code": "01-01", "type": "machine" },
        { "code": "04-11", "type": "machine" }
    ]
}

我想仅为类型为" machine"的标签获取不同的代码。因此,对于上面的示例,结果应为["01-01", "07-01", "04-11"]。 我该怎么做?

3 个答案:

答案 0 :(得分:1)

使用$unwind然后$group并将标记作为键,将在结果集的单独文档中为您提供每个标记:

db.collection_name.aggregate([
    {
        $unwind: "$tags"
    },
    {
        $match: { 
            "tags.type": "machine" 
        }
    },
    {
        $group: {
            _id: "$tags.code"
        }
    },
    {
        $project:{
            _id:false
            code: "$_id"
        }
    }
]);

或者,如果您希望将它们放入单个文档中的数组中,则可以在第二个$push阶段内使用$group

db.collection_name.aggregate([
    {
        $unwind: "$tags"
    },
    {
        $match: { 
            "tags.type": "machine" 
        }
    },
    {
        $group: {
            _id: "$tags.code"
        }
    },
    {
        $group:{
            _id: null,
            codes: {$push: "$_id"}
        }
    }
]);

另一位用户建议包括{ $match: { "tags.type": "machine" } }的初始阶段。如果您的数据可能包含大量不包含“machine”标记的文档,那么这是一个好主意。这样您就可以消除对这些文档的不必要处理。你的管道看起来像这样:

db.collection_name.aggregate([
    {
        $match: { 
            "tags.type": "machine" 
        }
    },
    {
        $unwind: "$tags"
    },
    {
        $match: { 
            "tags.type": "machine" 
        }
    },
    {
        $group: {
            _id: "$tags.code"
        }
    },
    {
        $group:{
            _id: null,
            codes: {$push: "$_id"}
        }
    }
]);

答案 1 :(得分:1)

> db.foo.aggregate( [
... { $unwind : "$tags" },
... { $match : { "tags.type" : "machine" } },
... { $group : { "_id" : "$tags.code" } },
... { $group : { _id : null , "codes" : {$push : "$_id"} }}
... ] )
{ "_id" : null, "codes" : [ "04-11", "07-01", "01-01" ] }

答案 2 :(得分:1)

更好的方法是直接在 tags.type 上分组,并在 tags.code 上使用 addToSet

以下是我们如何在3个聚合阶段实现相同的输出:

db.name.aggregate([
  {$unwind:"$tags"},

  {$match:{"tags.type":"machine"}},

  {$group:{_id:"$tags.type","codes":{$addToSet:"$tags.code"}}} 
])

输出:{“_ id”:“机器”,“代码”: [“04-11”,“07-01”,“01-01”] }

另外,如果您希望过滤掉tag.type代码,我们只需要在匹配阶段将“machine”替换为所需的tag.type。