2016-09-01 6 views
0

Мои документы выглядеть следующим образом:Distinct элемент массива с условием

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

Я хочу, чтобы получить различные коды только для тегов, тип которых «машина». поэтому для примера выше результат должен быть ["01-01", "07-01", "04-11"]. Как это сделать?

+0

Возможный дубликат [Как получить массив из коллекции mongoDB?] (Http://stackoverflow.com/questions/38210121/how-to-get-array-from-mongodb-collection) – styvane

ответ

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"} 
     } 
    } 
]); 
+0

Я предлагаю привести с '{$ match: {" tags.type ":" machine "}}', чтобы избавиться от любых документов, которые не будут вносить свой вклад. – cdbajorin

+0

Хорошее предложение. Обновлен ответ. – Wake

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" ] } 
1

Лучший способ бы группы непосредственно на tags.type и использовать addToSet на tags.code.

Вот как мы можем достичь того же выхода в 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.

Смежные вопросы