1

У меня есть набор данных, который выглядит примерно так:Проблема создания запроса в MongoDB с подзапроса

{ 
 
    "id": "02741544", 
 
    "items": [{ 
 
    "item": "A" 
 
    }] 
 
}, { 
 
    "id": "02472691", 
 
    "items": [{ 
 
    "item": "A" 
 
    }, { 
 
    "item": "B" 
 
    }, { 
 
    "item": "C" 
 
    }] 
 
}, { 
 

 
    "id": "01316523", 
 
    "items": [{ 
 
    "item": "A" 
 
    }, { 
 
    "item": "B" 
 
    }] 
 
}, { 
 
    "id": "01316526", 
 
    "items": [{ 
 
    "item": "A" 
 
    }, { 
 
    "item": "B" 
 
    }] 
 
}, { 
 
    "id": "01316529", 
 
    "items": [{ 
 
    "item": "A" 
 
    }, { 
 
    "item": "D" 
 
    }] 
 
},

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

{ 
 
    "item": "A", 
 
    "ids": [{ 
 
    "id": "02741544" 
 

 
    }, { 
 
    "id": "02472691" 
 

 
    }, { 
 
    "id": "01316523" 
 

 
    }, { 
 
    "id": "01316526" 
 

 
    }, { 
 
    "id": "01316529" 
 

 
    }] 
 
}, { 
 
    "item": "B", 
 
    "ids": [{ 
 
    "id": "02472691" 
 

 
    }, { 
 
    "id": "01316523" 
 

 
    }, { 
 
    "id": "01316526" 
 

 
    }] 
 
}, { 
 
    "item": "C", 
 
    "ids": [{ 
 
    "id": "02472691" 
 

 
    }] 
 
}, { 
 
    "item": "D", 
 
    "ids": [{ 
 
    "id": "02472691" 
 

 
    }] 
 
},

В принципе, я пытаюсь получить отдельные элементы из массива элементов в объекте, а затем возвращать массив идентификаторов для каждого объекта, который имеет этот элемент в массиве элементов.

ответ

2

Лучше использовать aggregation framework, в которой вам нужно запустить операцию, которая состоит из следующих этапов трубопровода (в указанном порядке):

  1. $unwind - Это первый шаг будет выравнивать items массив т.е. создает копию каждого документа на запись в массив. Это необходимо для обработки документов дальше по трубопроводу как «денормализованные» документы, которые можно объединить в группы.
  2. $group - Это будет группа уплощенных документов по ключу item поддокумента и создать ids список с помощью оператора аккумулятора в $push.

- ОБНОВЛЕНИЕ -

Как @AminJ отметил в комментариях, если items могут иметь одинаковые значения для отдельных предметов и вы не хотите дубликатов идентификаторов в результате вы можете использовать $addToSet вместо $push

Следующий пример демонстрирует это:

db.collection.aggregate([ 
    { "$unwind": "$items" }, 
    { 
     "$group": { 
      "_id": "$items.item", 
      "ids": { 
       "$push": { "id": "$id" } /* or use 
       "$addToSet": { "id": "$id" } if you don't want duplicate ids */      
      } 
     } 
    } 
]) 

Пример вывода

{ 
    "_id" : "A", 
    "ids" : [ 
     { "id" : "02741544" }, 
     { "id" : "02472691" }, 
     { "id" : "01316523" }, 
     { "id" : "01316526" }, 
     { "id" : "01316529" } 
    ] 
} 

/* 2 */ 
{ 
    "_id" : "B", 
    "ids" : [ 
     { "id" : "02472691" }, 
     { "id" : "01316523" }, 
     { "id" : "01316526" } 
    ] 
} 

/* 3 */ 
{ 
    "_id" : "C", 
    "ids" : [ 
     { "id" : "02472691" } 
    ] 
} 

/* 4 */ 
{ 
    "_id" : "D", 
    "ids" : [ 
     { "id" : "01316529" } 
    ] 
} 

Результат от aggregate() функции курсор к документам, произведенных на заключительном этапе операции агрегации трубопровода. Поэтому, если вы хотите получить результаты в массиве, вы можете использовать метод курсора toArray(), который возвращает массив, содержащий все документы из него.

Например:

var pipeline = [  
     { "$unwind": "$items" }, 
     { 
      "$group": { 
       "_id": "$items.item", 
       "ids": { 
        "$push": { "id": "$id" } /* or use 
        "$addToSet": { "id": "$id" } if you don't want duplicate ids */      
       } 
      } 
     } 
    ], 
    results = db.collection.aggregate(pipeline).toArray(); 

printjson(results); 
+1

Может быть, стоит отметить, если '' деталей может иметь дублирующие 'item' значения, и вы не хотите дублировать идентификаторы в результате вы можете использовать 'addToSet' вместо' push'. –

+0

@AminJ Хорошая точка – chridam

+0

Это дает желаемый результат, пока контент идет, но он не возвращает результаты в виде массива объектов. Как это делается? – TWLATL

0

Вот решение с использованием агрегирования трубопровода:

db.col.aggregate([ 
     { 
      $unwind: "$items" 
     }, 
     { 
      $project: { 
       id: 1, 
       item: "$items.item" 
      } 
     }, 
     { 
      $group: { 
       _id: "$item", 
       ids: { 
        $push: "$id" 
       } 
      } 
     } 
    ])