Поиск только элемента в массиве массивов по значению с помощью Mongoose

#node.js #mongodb #mongoose #mongodb-query #aggregation-framework

#node.js #mongodb #mongoose #mongodb-запрос #агрегация-фреймворк

Вопрос:

Вот пример моей схемы с некоторыми данными:

 client {
  menus: [{
    sections: [{
      items: [{
        slug: 'some-thing'
      }]
    }]
  }]
}
  

И я пытаюсь выбрать его следующим образом:

 Schema.findOne({ client._id: id, 'menus.sections.items.slug': 'some-thing' }).select('menus.sections.items.$').exec(function(error, docs){
  console.log(docs.menus[0].sections[0].items[0].slug);
});
  

Конечно, «docs.menus [0].sections [0].items [0].slug» работает только в том случае, если в каждом массиве есть только одна вещь. Как я могу заставить это работать, если в каждом массиве есть несколько элементов, без необходимости перебирать все, чтобы найти его?

Если вам нужна более подробная информация, дайте мне знать.

Комментарии:

1. Итак, ваш вопрос на самом деле заключается в том, что несколько menus.sections.items.slug могут соответствовать «чему-то», и вы хотите вернуть их все, а не только один. Или вы имеете в виду что-то другое?

2. Нет, пуля уникальна и должна возвращать только одну вещь, но она возвращает все содержимое в родительских массивах… поэтому использование [0] не работает.

3. Ваша цитата «Как я могу заставить это работать, если в каждом массиве есть несколько элементов» Я прошу вас объяснить, что вы имеете в виду, если не соответствует более чем одному элементу, как следует из вашего вопроса.

4. Мой вопрос написан плохо.. Что-то вроде Schema.findOne({client._id: id, ‘меню. _id’: id }).select(‘menus.$’) … вернет массив с одним элементом, т.е.. docs.menus[0] … есть ли способ сделать это, когда вы глубже, чем один массив (массив внутри массива)?

5. По сути, я только хочу, чтобы он возвращал соответствующее меню, раздел, элемент… не все меню, разделы и т.д.

Ответ №1:

Структура агрегации хороша для поиска объектов в глубоко вложенных массивах, где позиционный оператор вас подведет:

 Model.aggregate(
    [
       // Match the "documents" that meet your criteria
       { "$match": {
           "menus.sections.items.slug": "some-thing"
       }},

       // Unwind the arrays to de-normalize as documents
       { "$unwind": "$menus" },
       { "$unwind": "$menus.sections" },
       { "$unwind": "$menus.sections.items" }


       // Match only the element(s) that meet the criteria
       { "$match": {
           "menus.sections.items.slug": "some-thing"
       }}

       // Optionally group everything back to the nested array
       // One step at a time
       { "$group": {
           "_id": "$_id",
           "items": { "$push": "$menus.sections.items.slug" }
       }},
       { "$group": {
           "_id": "$_id",
           "sections": { 
               "$push": { "items": "$items" }
           }
       }},
       { "$group": {
           "_id": "$_id",
           "menus": { 
               "$push": { "sections": "$sections" }
           }
       }},
    ],
    function(err,results) {

    }
)
  

Также см. Другие операторы агрегирования, например, $first для сохранения других полей в вашем документе при использовании $group .