How to update nested object in array (Mongoose/MongoDB)

Issue

I’ve been struggling to get my around how to update a object in a nested array with a particular id. I’ve attempted to implement $set as shown below. I want to be able to update the task with an _id of 62ff74bfe80b11ade2d34455 with the data from the request body.

{
    "_id": "62fa5aa25778ec97bc6ee231",
    "user": "62f0eb5ebebd0f236abcaf9d",
    "name": "Marketing Plan",
    "columns": [
        {
            "name": "todo",
            "_id": "62fa5aa25778ec97bc6ee233",
            "tasks": [
                {           ====> here
                    "title": "Task Four",
                    "description": "This is task four",
                    "subtasks": [
                        {
                            "name": "wash dshes",
                            "completed": false,
                            "_id": "62ff74bfe80b11ade2d34456"
                        },
                        {
                            "name": "do homework",
                            "completed": false,
                            "_id": "62ff74bfe80b11ade2d34457"
                        }
                    ],
                    "_id": "62ff74bfe80b11ade2d34455"
                }
            ]
        },
        {
            "name": "doing",
            "_id": "62fa5aa25778ec97bc6ee234",
            "tasks": []
        },
        {
            "name": "done",
            "_id": "62fa5aa25778ec97bc6ee235",
            "tasks": []
        }
    ],
    "__v": 0
}
    const updatedTask = await Board.findOneAndUpdate(
        {
          "columns.tasks._id": req.params.id,
        },
        { $set: { "columns.$.tasks": req.body } },
        { new: true }
      );

Solution

You can use the positional operator in combination with an arrayfilter. Here’s an example how you’d update a specific field of the relevant task:

db.collection.update({
  "columns.tasks._id": req.params.id
},
{
  "$set": {
    "columns.$[].tasks.$[t].title": "it works"
  }
},
{
  "arrayFilters": [
    {
      "t._id": req.params.id
    }
  ]
})

You can also try this on mongoplayground.

If you’re looking for a way to replace the matching task object itself you can do:

db.collection.update({
      "columns.tasks._id": req.params.id
    },
    {
      "$set": {
        "columns.$[].tasks.$[t]": req.body
      }
    },
    {
      "arrayFilters": [
        {
          "t._id": req.params.id
        }
    ]
})

Answered By – eol

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published