2015-08-07 2 views
4

У меня есть коллекция данных MongoDB, который выглядит следующим образом:Как объединить два массива полей во многих документах в один набор?

{ "_id" : "1", "array1" : [ "1", "2" ] }, 
{ "_id" : "2", "array2" : [ "1", "3" ] }, 
{ "_id" : "3", "array1" : [ ] }, 
{ "_id" : "4", "array2" : [ ] }, 
{ "_id" : "5" }, 
{ "_id" : "6", "array1" : [ "3", "4" ], "array2" : [ "5" ] } 

Я хотел бы найти запрос, который просто возвращает уникальные значения массива в одном массиве, как так:

{"_id":"theID", "result":["1", "2", "3", "4", "5"]} 

id не имеет значения. Обратите внимание, что либо array1, array2, либо оба они могут присутствовать в документе и что они могут даже быть пустыми. Я пробовал много агрегаций и каскадных команд запроса и просто не могу найти желаемого ответа.

+0

Это не так просто, как я думал, что это будет. Моя идея состояла в том, чтобы сначала скрутить оба массива в один, используя '$ setUnion', затем' $ unwind' результирующий массив, а затем '$ group' с помощью' $ addToSet', но, к сожалению, '$ setUnion' не работает, если оба поля содержатся в документе. – Philipp

ответ

4

Для этого вам необходимо использовать метод .aggregate(), который обеспечивает доступ к конвейеру агрегации.

Первый этап в трубопроводе используется оператор $match, чтобы отфильтровать те документы, где оба array1 и array2 не являются подарки с помощью $exists оператора и dot notation. Этот оператор сокращает количество документов, подлежащих обработке в нисходящем конвейере.

Следующий этап: $project, где вы в основном используете $setUnion для возврата массива, содержащего элементы, которые отображаются в любом из ваших массивов; он также отфильтровывает дубликаты элементов в своем результате. Также не используется оператор $ifNull, который возвращает значение первого выражения или пустого массива в зависимости от того, имеет ли первое выражение значение null (здесь выражение «array1» и «array2»). Оттуда вам необходимо де-нормализовать поле «массивы», используя оператор $unwind.

На последнем этапе трубопровода вы используете $group и используете операционный аккумулятор $addToSet, который возвращает массив уникального значения.

db.getCollection('collection').aggregate([ 
    { "$match": { 
     "$or": [ 
      { "array1.0": { "$exists": true } }, 
      { "array2.0": { "$exists": true } } 
     ] 
    }}, 
    { "$project": { 
     "arrays": { 
      "$setUnion": [ 
       { "$ifNull": [ "$array1", [] ] }, 
       { "$ifNull": [ "$array2", [] ] } 
      ] 
     } 
    }}, 
    { "$unwind": "$arrays" }, 
    { "$group": { 
     "_id": null, 
     "arrays": { "$addToSet": "$arrays" } 
    }} 
]) 

Что дает:

{ "_id" : null, "arrays" : [ "5", "3", "1", "4", "2" ] } 
+0

с использованием '$ ifNull' важен с' $ setUnion', иначе вы получите NULL, если один массив пуст – sidonaldson

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