Home > OS >  Push an object into a nested array in MongoDB
Push an object into a nested array in MongoDB

Time:01-13

I've got a head-scratcher here that I'd like to share with you all.

So here's the model:

    _id: ObjectId()
    name: String,
    columns: [
      {
        name: String,
        _id: ObjectId()
        tasks: [
          {
            title: String,
            description: String,
            status: String,
            _id: ObjectId()
            subtasks: [
              {
                title: String,
                isCompleted: Boolean,
              },
            ],
          },
        ],
      },
    ],
  });

and the query:

exports.createSubtask = (req, res) => {
  if (!req.body) {
    res.status(400).send({ message: "Task name can not be empty!" });
    return;
  }

  const board = req.params.board;
  const column = req.params.column;
  const task = req.params.task;

  Board.findOneAndUpdate(
    {
      _id: board,
      "columns._id": column,
      "columns.tasks._id": task,
    },
    {
      $push: {
        "columns.$.tasks.$.subtasks": req.body,
      },
    }
  )
    .then((data) => {
      if (!data) {
        res.status(404).send({
          message: `Cannot update Task with id=${task}. Maybe task was not found!`,
        });
      } else res.send({ message: "Task was updated successfully." });
    })
    .catch((err) => {
      res.status(500).send({
        message: "Error updating Task with id="   task,
      });
    });
};

I'm trying to push an object into the subtasks array with $push, but Postman is throwing an error.

Any ideas as to what I'm doing wrong? Appreciate the help.

  • Golden Ratio

However, I was able to successfully push an object into the tasks array with the following query:

exports.createTask = (req, res) => {
  if (!req.body) {
    res.status(400).send({ message: "Task name can not be empty!" });
    return;
  }

  const board = req.params.board;
  const column = req.params.column;

  Board.findOneAndUpdate(
    {
      _id: board,
      "columns._id": column,
    },
    {
      $push: {
        "columns.$.tasks": req.body,
      },
    }
  )
    .then((data) => {
      if (!data) {
        res.status(404).send({
          message: `Cannot update Column with id=${column}. Maybe column was not found!`,
        });
      } else res.send({ message: "Column was updated successfully." });
    })
    .catch((err) => {
      res.status(500).send({
        message: "Error updating Column with id="   column,
      });
    });
};

CodePudding user response:

It is not possible to use multiple positional $ for the nested array as mention in docs:

The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value

You should work with the positional filtered operator $[<identifier>].

Board.findOneAndUpdate(
    {
      _id: board,
      "columns._id": column,
      "columns.tasks._id": task,
    },
    {
      $push: {
        "columns.$.tasks.$[task].subtasks": req.body,
      },
    },
    {
      arrayFilters: [
        { "task._id": task }
      ]
    }
  )
.then(...);

Note: Ensure that the passed in task is ObjectId type.

CodePudding user response:

Credit to Yong Shun Yong for the help. Through trial and error, I solved the problem with the following code

 Board.findOneAndUpdate(
{
  _id: board,
  "columns._id": column,
},
{
  $push: {
    "columns.$.tasks.$[].subtasks": req.body,
  },
},
{
  arrayFilters: [{ "task._id": task }],
}

)

  • Related