how can I make the "updated" of mongodb stop when updating a field of a nested array?

Viewed 100

I have a database like this:

  {
        "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"
                 }
              ]
           }
        ]
     }

And with this code, I update the field 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
  }

)

I want to just update the first object where there is a match, and stop it.

For example, if I have an array of 100,000 elements and the object where the match is, is in the tenth position, he will update that record, but he will continue going through the entire array and this seems ineffective to me even though he already did the update.

Note: if I did the update using an _id inside of universe.saga.characters instead of doing the update using the name, it would still loop through the rest of the elements.

How can I do it?

1 Answers

Update using arrayFilters conditions

I don't think it will find and update through loop, and It does not matter if collection have 100,000 sub documents, because here is nice explanation in $[<identifier>] and has mentioned:

  • The $[<identifier>] to define an identifier to update only those array elements that match the corresponding filter document in the arrayFilters

  • In the update document, use the $[<identifier>] filtered positional operator to define an identifier, which you then reference in the array filter documents. But make sure you cannot have an array filter document for an identifier if the identifier is not included in the update document.

Update using _id

Your point,

Note: if I did the update using an _id inside of universe.saga.characters instead of doing the update using the name, it would still loop through the rest of the elements.

MongoDB will certainly use the _id index. Here is the nice answer on question MongoDB Update Query Performance, from this you will get an better idea on above point

Update using indexed fields

You can create index according to your query section of update command, Here MongoDB Indexes and Indexing Strategies has explained why index is important,

In your example, lets see with examples:

Example 1: If document have 2 sub documents and when you update and check with explain("executionStats"), assume it will take 1 second to update,

quick use Mongo Playground (this platform will not support update query)

Example 2: If document have 1000 sub documents and when you update and check with explain("executionStats"), might be it will take more then 1 second,

If provide index on fields (universe, saga.characters.character and saga.characters.picture) then definitely it will take less time then usual without index, main benefit of index it will direct point to indexed fields.

quick use Mongo Playground (this platform will not support update query)

Create Index for your fields

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

For more experiment use above 2 examples data with index and without index and check executionStats you will get more clarity.

Related