首页 > 解决方案 > 更新嵌套数组的字段时,如何使 mongodb 的“更新”停止?

问题描述

我有一个这样的数据库:

  {
        "universe":"comics",
        "saga":[
           {
              "name":"x-men",
              "characters":[
                 {
                    "character":"wolverine",
                    "picture":"618035022351.png"
                 },
                 {
                    "character":"wolverine",
                    "picture":"618035022352.png"
                 }
              ]
           }
        ]
     },
     {
        "universe":"dc",
        "saga":[
           {
              "name":"spiderman",
              "characters":[
                 {
                    "character":"venom",
                    "picture":"618035022353.png"
                 }
              ]
           }
        ]
     }

使用这段代码,我更新了 where 字段name: wolverine

db.getCollection('collection').findOneAndUpdate(
  {
    "universe": "comics"
  },
  {
    $set: {
      "saga.$[outer].characters.$[inner].character": "lobezno",
      "saga.$[outer].characters.$[inner].picture": "618035022354.png"
    }
  },
  /*{
    "saga.characters": 1
  },*/
  {
    "arrayFilters": [
      {
        "outer.name": "x-men"
      },
      {
        "inner.character": "wolverine"
      }
    ],
      "multi":false
  }

)

我只想更新第一个匹配的对象,然后停止它。

例如,如果我有一个包含 100,000 个元素的数组,并且匹配的对象位于第十位,他将更新该记录,但他将继续遍历整个数组,这对我来说似乎无效,即使他已经做了更新。

注意:如果我使用_idinside 进行 universe.saga.characters更新而不是使用 进行更新name,它仍然会循环遍历其余元素。

我该怎么做?

标签: mongodb

解决方案


使用arrayFilters条件更新

我不认为它会通过循环查找和更新,如果集合有 100,000 个子文档也没关系,因为这里在$[<identifier>]中有很好的解释,并提到:

  • $[<identifier>]定义一个标识符,只更新那些匹配对应过滤器文档的数组元素arrayFilters

  • 在更新文档中,使用$[<identifier>]过滤后的位置运算符定义一个标识符,然后在数组过滤器文档中引用该标识符。但是,如果标识符未包含在更新文档中,请确保您不能拥有标识符的数组过滤文档。

使用更新_id

你的观点,

注意:如果我使用_id内部universe.saga.characters而不是使用名称进行更新,它仍然会循环遍历其余元素。

MongoDB 肯定会使用_id索引。这是关于MongoDB Update Query Performance问题的不错答案,从这里您将对上述问题有更好的了解

使用索引字段更新

您可以根据更新命令的查询部分创建索引,这里MongoDB Indexes and Indexing Strategies解释了为什么索引很重要,

在您的示例中,让我们看一下示例:

示例 1:如果文档有 2 个子文档,并且当您使用explain("executionStats")更新和检查时,假设更新需要 1 秒,

快速使用Mongo Playground (本平台不支持更新查询)

示例 2:如果文档有 1000 个子文档,并且当您使用explain("executionStats")更新和检查时,可能需要超过 1 秒,

如果在字段(和)上提供索引universe,那么肯定会比没有索引花费更少的时间,索引的主要好处是它将直接指向索引字段。saga.characters.charactersaga.characters.picture

快速使用Mongo Playground (本平台不支持更新查询)

为您的字段创建索引

db.maxData.createIndex({ 
    "universe": 1, 
    "saga.characters.character": 1, 
    "saga.characters.picture": 1
})

如需更多实验,请使用以上 2 个带索引和不带索引的示例数据,并检查executionStats您将获得更清晰的结果。


推荐阅读