Search code examples
node.jsmongodbmongoose

How to update multiple array of object fields in the most efficient manner using mongoose


Let's say I have the following data document in Mongo:

{ id: '1',
  collaborators: [ 
   { name: "name 1",
     email: "email 1",
     rating: null
   },
   { name: "name 2",
     email: "email 2",
     rating: null
   }],
   social: [
   { type: "type A",
     message: "message A",
     response: false
   },
   { type: "type B",
     message: "message B",
     response: false
   }]
}

and I need to update both email 1 and type B objects in their respective arrays from the returned data.

I know I can run a positional operator update in two separate calls i.e. something like:

await model.findOneAndUpdate({_id: 1, collaborators.email: "email1"}, {$set: { "collaborators.$.rating: 5"}})
await model.findOneAndUpdate({_id: 1, social.type: "typeB"}, {$set: { "social.$.response: true"}})

and I could probably use bulkWrite to make it more efficient, as I'll end up with a lot more of these in production, but can I just run one query to update both arrays ?


Solution

  • Credit goes to @joe for bringing up the idea of using arrayFilters

    You can specify matched element position through the usage of arrayFilters and update the referenced element.

    db.collection.update({},
    {
      $set: {
        "collaborators.$[c].rating": 5,
        "social.$[s].response": true
      }
    },
    {
      arrayFilters: [
        {
          "c.email": "email 1"
        },
        {
          "s.type": "type B"
        }
      ]
    })
    

    Mongo Playground


    One of the side notes is that you may want to consider refactoring the schema to separate collaborators and social into different documents/collections. It could be contradicting your requirement of minimizing db calls but they seem like independent information from the context I observed in the post. Separating them can bring benefits of simpler code and potential performance boost through indexing.