MongoDB:更新嵌套数组文档中的子属性

时间:2016-12-21 07:59:00

标签: mongodb mongoose loopbackjs mongojs

我的结构如下所示:

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。假设cardID是301.我没有关于课程或卡存储部分的详细信息。我只有cardID。我想将卡片名称从“测试1”更新为“测试2”。

请提供一些有关如何仅更新cardId更新卡名称的信息。另外,请提供有关如何仅使用cardId访问单张卡的信息。

如果我运行以下查询:

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

返回整个section对象而不是返回单个卡。请提供一些有关如何仅使用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"
               }
         ]
      }
   ] 
}

请提供有关如何仅使用卡ID更新卡的信息。

假设我要更改卡的名称。我如何实现它?

1 个答案:

答案 0 :(得分:3)

我希望这个答案足以满足您的需求:

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. 首先,您需要aggregate(找到mongojsmongoose等任何库,以及如何在各自的手册中执行此操作),
  2. 然后是unwind部分和卡片。
  3. 完成这两个步骤后,您需要根据您的要求unwind操作filter文档生成Clear个文档。在这种情况下:哪张卡与您的ID匹配
  4. mapReduce您不需要的任何属性
  5. 返回结果
  6. 更新文档内的属性:

    在不知道其索引的情况下更新数组内部的元素是不可能的,因此首先,您必须在其中找到其索引/位置。我能想到的最简单的方法是使用for(因为你的是双层数组,我认为$lookup方法会复杂得多):

    // 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为这种应用引入了sudo in php exec()

    它不仅可以让您的生活更轻松,还可以让mongo查询运行得更快。