MongoDB: Обновление вложенных свойств в документе с вложенным массивом

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

course: { // course 
   id,
   coursename,
   sections: { // has an array of sections
    section: {
      id,
      sectionname
      cards: {  // each section has an array of cards
         card: {
            id  
            cardname 
         }
      }
    }
  }
}

Теперь мне дали ID карты. Предположим, что card ID - 301. У меня нет сведений о курсе или разделе, в котором хранится карта. У меня есть только идентификатор карты. Я хочу обновить имя карты с "Тест 1" до "Тест 2".

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

Если я запускаю следующий запрос:

 db.course.find( {"sections.cards.id" : ObjectId("5859517447c4286d0f0639ee")},
{"sections.cards.$":1,_id:0})

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

Пример документа, который у меня есть:

{ 
   "_id" : ObjectId("58595041cfdc46100f92a985"), 
   "modelType" : "Course",
   "name" : "c1",
   "sections" : [ 
        { 
           "id" : ObjectId("5859504dcfdc46100f92a986"),
           "name" : "s1", 
           "cards" : [ 
               { 
                  "id" : ObjectId("58595057cfdc46100f92a987"),
                  "name" : "card1", 
               }, 
               { 
                  "id" : ObjectId("5859506ccfdc46100f92a988"),
                  "name" : "card2"
               }
         ]
      }
   ] 
}

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

Предположим, я хочу изменить имя карты. Как мне этого добиться?

1 ответ

Решение

Надеюсь, этого ответа достаточно для ваших нужд:

db.collection.aggregate([
   {$unwind: "$sections"}, // unwind the array
   {$unwind: "$sections.cards"}, // unwind the array
   {$match: {"sections.cards.id": ObjectId("5859506ccfdc46100f92a988")}}, // filter
   {$project: {_id: 0, id: "$sections.cards.id", name: "$sections.cards.name"}} // cut and clear any property that you don't need
])

какой результат в (я проверил это, используя ваш образец):

{
   "name" : "card2",
   "id" : ObjectId("5859506ccfdc46100f92a988")
}

Объяснение:

  1. Прежде всего, вам нужно объединить (найти любую библиотеку, как mongojs или же mongoose и как это сделать в соответствующем руководстве),
  2. затем раскрутите разделы и карточки внутри.
  3. После обоих шагов необходимо отфильтровать документы, полученные в результате unwind Операция по вашему требованию. В этом случае: какая карта соответствует вашему ID
  4. Очистите любые свойства, которые вам не нужны
  5. Вернуть результат

Чтобы обновить свойства внутри документа:

Невозможно обновить элемент внутри массива без знания его индекса, поэтому сначала вы должны выяснить его индекс / позицию внутри. Самый простой способ, которым я мог придумать, это использовать for (поскольку у вас двухуровневый массив, я думаю, что метод mapReduce будет намного сложнее):

// first, find the document, where xxx is the target card ID
db.collection.find({'sections.cards.id': ObjectId("xxx")}, function(err, reply){
     // iterates through the documents
     for(var z = 0; z < reply.length; z++){
         // iterates through the `sections`
         for(var y = 0; y < reply[z].sections.length; y++){
             // iterates through the `cards`
             for(var x = 0; x < reply[z].sections[y].cards.length; x++){
                  if(reply[z].sections[y].cards[x].id.toString() === "xxx")                   
                  {
                       // do what you want to do the card here
                       reply[z].sections[y].cards[x].name = "updated name";
                  }
             }
         }

         // save the updated doc one-by-one,
         db.collection.update({_id: reply._id}, reply);
     }


});

Лучшее решение

Лучшее решение: у вас такого документа нет. Подход к базе данных без схемы не означает, что вы можете поместить все в документ. Вы должны были рассмотреть функциональность и доступность данных при следующем проектировании схемы документа.

Вы можете рационализировать документы в соответствии с вашими потребностями. В этом случае вы должны разделить course документ, так как ясно, что card собственность должна быть независимой коллекцией от course, Если вы беспокоитесь о том, что вам нужно присоединиться к обеим коллекциям, не беспокойтесь. Начиная с 3.2, mongodb ввел $ lookup для такого рода приложений.

Это не только облегчит вам жизнь, но и ускорит выполнение запросов на монго.

Другие вопросы по тегам