How to Update Deeply Nested Array in MongoDB/ Mongoose

Recently I have finished Legacy Full-Stack course on FCC, and as a part of checking my skills I am trying to build a MERN platform. Currently I am at the point of building RESTful API connected to the MongoDB with Mongoose. Most of the routes are ready, but I am stuck for nearly two days on one seemingly simple thing. I have an array with reviews, nested 2 levels inside of a model. What I want to do is pass 3 parameters in the query, and use them to localize the object in the array and replace it’s content on PUT method. I have tried Model.updateOne method with $set attribute, however this one overides the whole array and othe elements are gone, when I use $push instead it add’s duplicated object. I have been looking for the answer pretty much everywhere but I am stuck. Below you can have a look at my code, and link to GItHub repo is also attached.

Thanks in advance! :slight_smile:

exports.EditReview = async (req, res) => {
  try {
    const result = reviewSchema.validate(req.body);
    if (result.error) {
      console.log(result.error.message);
      return res.json({
        error: true,
        status: 400,
        message: result.error.message,
      });
    }

    const tempCar = await Car.updateOne(
      {
        make: req.params.make,
        models: {
          $elemMatch: {
            name: req.params.model,
            "models.$.reviews._id": req.params._id,
          },
        },
        // "models.name": req.params.model,
        //   "reviews._id": req.params._id,
      },
      { $set: { "models.$.reviews": result.value } }
    );

    console.log(tempCar);

    return res.status(200).json({
      success: true,
      message: "Review added to the DB",
    });
  } catch (error) {}
  console.error(error);
  return res.status(500).json({
    error: true,
    message: "Cannot add the car review",
  });
};

https://github.com/KowalewskiPawel/reviwIT-Server/blob/main/cars/car.controller.js

I see that no one could solve to the problem so I found the solution myself. If you have many nested arrays inside of your object, you should target each of them with arrayFilters option. The same can be applied while removing the element from the array. ArrayFilter option let you target each of the element of the given array manualy using some kind of temporary variable. Below you can find my code, I think it is kind of self-explanatory, still if you have problems in understanding feel free to ask.

Updating Array

const tempCar = await Car.findOneAndUpdate(
      {
        make: req.params.make,
      },
      { $set: { "models.$[e1].reviews.$[e2]": result.value } },
      {
        arrayFilters: [
          { "e1.name": req.params.model },
          { "e2._id": req.params._id },
        ],
      }
    );

Deleting Element from the array

 const tempCar = await Car.findOneAndUpdate(
      {
        make: req.params.make,
      },
      { $pull: { "models.$[e1].reviews": { _id: req.params._id } } },
      {
        arrayFilters: [
          { "e1.name": req.params.model },
          { "e2._id": req.params._id },
        ],
      }
    );
4 Likes

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.