How do I update an object in a deeply nested array of objects with mongoose?

50 Views Asked by At

I am trying to update the value of an object in a deeply nested array in mongoose, but havn't been able to come up with the correct syntax.

I have tried both atomic updates and the conventional way of updating items in mongodb still with no luck.

I want to update 'history[index].rideConfirmations[index].rideComplete.driverConfirmed

//driverHistorySchema.js
const mongoose = require("mongoose");

const DriversRideHistorySchema = new mongoose.Schema(
  {
    driverId: mongoose.Schema.ObjectId,
    driverName: String,
    history: [
      {
        date: String,
        rideConfirmations: [
          {
            riderConfirmationTime: String,
            driverConfirmationTime: String,
            riderName: String,
            riderId: mongoose.Schema.ObjectId,
            rideComplete: {
              riderConfirmed: Boolean,
              driverConfirmed: Boolean,
            },
          },
        ],
      },
    ],
  },
  { timestamps: true, collection: "driversRideHistory" }
);

module.exports = mongoose.model("DriversRideHistory", DriversRideHistorySchema);


I want to update 'history[index].rideConfirmations[index].rideComplete.driverConfirmed

router.put("/rideHistory/completeRide", async (req, res) => {
  try {
    const { driverId, dateIndex, riderIndex } = req.body;

    await DriversHistoryModel.findOneAndUpdate(
      {
        driverId: driverId,
      },
      {
        $set: {
          "history.$[dateIndex].rideConfirmations.$[riderIndex].rideComplete.driverConfirmed": true,
        },
      },
      { arrayFilters: [{ dateIndex: dateIndex }, { riderIndex: riderIndex }] }
    );

    return res.status(200).send("Ride Completed Successfully");
  } catch (err) {
    console.log(err);
    return res
      .status(404)
      .send("An error occured while processing this request");
  }
});

module.exports = router;
3

There are 3 best solutions below

0
user3118363 On BEST ANSWER
router.put("/rideHistory/completeRide", async (req, res) => {
  console.log(req.body);
  try {
    const { driverId, dateIndex, riderIndex } = req.body;
    //Update history on driver's profile first
    const driver = await DriversHistoryModel.findOne({
      driverId,
    });

    const dateToUpdate =
      driver.history[dateIndex].rideConfirmations[riderIndex];

    dateToUpdate.rideComplete.driverConfirmed = true;

    await driver.save();

    return res.status(200).send(dateToUpdate);


    return res.status(200).send("Ride Completed Successfully");
  } catch (err) {
    console.log(err);
    return res
      .status(404)
      .send("An error occured while processing this request");
  }
});
0
blackrio On

To update the value of an object in a deeply nested array in Mongoose, you can use the positional $ operator combined with the dot notation. Here's a basic example:

DriverHistoryModel.findOneAndUpdate(
      { "nestedArray._id": objectIdOfParentDocument, "nestedArray.nestedArray2._id": objectIdOfNestedDocument },
      { $set: { "nestedArray.$.nestedArray2.$[elem].propertyName": newValue } },
      { arrayFilters: [{ "elem._id": objectIdOfDesiredElement }] },
      function(err, doc) {
        // Handle error or updated document
      }
    );
0
Tarun Agarwal On

In your code, you are using the $set operator along with the arrayFilters option, which is the right approach. However, you have to make sure that the variables dateIndex and riderIndex are defined and have the correct values.

Here's an adjusted version of your code:

router.put("/rideHistory/completeRide", async (req, res) => {
  try {
    const { driverId, dateIndex, riderIndex } = req.body;
    if (dateIndex === undefined || riderIndex === undefined) {
      return res.status(400).send("Invalid dateIndex or riderIndex");
    }

    await DriversHistoryModel.findOneAndUpdate({ driverId: driverId },
      {
        $set: {
          [`history.${dateIndex}.rideConfirmations.${riderIndex}.rideComplete.driverConfirmed`]: true,
        },
      }
    );

    return res.status(200).send("Ride Completed Successfully");
  } catch (err) {
    console.log(err);
    return res.status(404).send("An error occurred while processing this request");
  }
});

module.exports = router;

In this adjusted version: The dateIndex and riderIndex are used directly in the $set operator with template literals to dynamically construct the path to the nested field.