【问题标题】:MongoDB: Updating a sub properties inside a nested array documentMongoDB:更新嵌套数组文档中的子属性
【发布时间】:2016-12-21 07:58:59
【问题描述】:

我的结构如下所示:

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。我想将卡名从“Test 1”更新为“Test 2”。

请提供一些关于如何在仅给定 cardId 的情况下更新卡片名称的信息。另请提供有关如何仅使用 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"
               }
         ]
      }
   ] 
}

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

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

【问题讨论】:

  • 你想做什么?您可以发布文件作为示例吗?不清楚哪个属性是你的数组,哪个是你的对象
  • @DennyHiu,我添加了一个示例文档。我想只使用卡片 ID 获取特定卡片。
  • @MaulikSoneji 你试过$elemMatch 吗?
  • @Yogesh,我已经编写了上面尝试过的查询。我不知道 $elemMatch。您能否提供更多解释或编写查询来这样做?
  • @MaulikSoneji 我刚刚写了一个答案,希望它是你需要的。随意问:)

标签: mongodb mongoose loopbackjs mongojs


【解决方案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. 首先,您需要 aggregate(查找任何库,如 mongojsmongoose 以及如何在各自的手册中执行此操作),
  2. 然后是unwind 里面的部分和卡片。
  3. 完成这两个步骤后,您需要根据您的要求对filter 操作产生的unwind 文件进行处理。在这种情况下:哪张卡与您的身份证相符
  4. Clear 任何你不需要的属性
  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

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

【讨论】:

  • 另外,请提供有关如何更新卡的信息。
  • 恐怕您需要单独的函数来更新此文档。最简单的方法是使用update 方法。我会尽快更新我的答案
猜你喜欢
  • 1970-01-01
  • 2016-11-23
  • 2017-04-28
  • 1970-01-01
  • 2013-03-19
  • 2014-09-23
  • 2014-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多