Search code examples
node.jsmongodbnestedmongoose-schemaput

Unable to update mongodb document with nested object property from node api


I have the following mongodb document:

{
    "_id" : ObjectId("5ee95b41ca023a3deb252ef2"),
    "uid" : "jdoe",
    "name" : "John Doe",
    "employee_hire_date" : "2012-06-20",
    "three_month_review_target" : "2012-09-20",
    "six_month_review_target" : "2012-12-20",
    "three_month_review_status" : {
        "is_scheduled" : null,
        "is_team_member_emailed" : null,
        "is_review_executed" : null,
    },
    "six_month_review_status" : {
        "is_scheduled" : null,
        "is_team_member_emailed" : null,
        "is_review_executed" : null,
    }
}

I would like to update the three_month_review_status.is_scheduled nested property to true. I am using a put request to accomplish this:

const mongoose = require('mongoose');
const Reviews = require('../modules/reviews/models/reviews');

module.exports = (app) => {
    app.put('/api/reviews/isScheduled', async (req, res) => {
        console.log('body', req.body)
        console.log('uid', req.body.uid)
        console.log('is_scheduled', req.body.three_month_review_status.is_scheduled)
        Reviews.findOneAndUpdate( { 'uid': req.body.uid }, { $set: { 'three_month_review_status.is_scheduled': req.body.is_scheduled }}, (err, result) => {
            if (err) {
                console.log('error', err)
            }
             else {
                console.log('updated', result);
                res.status(200).send(result);
            }
        } )
    });
}

To test this, I execute this PUT request through Postman with the following request body:

{
    "uid": "jdoe",
    "three_month_review_status": {
        "is_scheduled": "true"
    }
}

However, when the request gets executed, the other two nested objects are removed and is_scheduled remains null. This is the document after the request is executed:

{
    "_id" : ObjectId("5ee95b41ca023a3deb252ef2"),
    "uid" : "jdoe",
    "name" : "John Doe",
    "employee_hire_date" : "2012-06-20",
    "three_month_review_target" : "2012-09-20",
    "six_month_review_target" : "2012-12-20",
    "three_month_review_status" : {
        "is_scheduled" : null
    },
    "six_month_review_status" : {
        "is_scheduled" : null,
        "is_team_member_emailed" : null,
        "is_review_executed" : null,
    }
}

What am I doing wrong? Here is my reviewsSchema for more context:

const { Schema, model } = require('mongoose');

const reviewsSchema = new Schema({
    uid: String,
    name: String,
    employee_hire_date: String,
    three_month_review_target: String,
    six_month_review_target: String,
    three_month_review_status: {
        is_scheduled: Boolean,
        is_team_member_emailed: Boolean,
        is_review_executed: Boolean,
    },
    six_month_review_status: {
        is_scheduled: Boolean,
        is_team_member_emailed: Boolean,
        is_review_executed: Boolean,
    },
})

const Reviews = model('review', reviewsSchema);

module.exports = Reviews;

Solution

  • In Mongoose you don't need to specify the $set. Also based on the sample JSON that you send from the postman instead of req.body.is_scheduled you need to provide req.body.three_month_review_status.is_scheduled in the query. Also, need to add {new: true} if you want the findOneAndUpdate to return the updated document

    So you can update the query like

    Reviews.findOneAndUpdate(
      { uid: req.body.uid },
      {
        "three_month_review_status.is_scheduled":
          req.body.three_month_review_status.is_scheduled,
      },
      { new: true },
      (err, result) => {
        if (err) {
          console.log("error", err);
        } else {
          console.log("updated", result);
          res.status(200).send(result);
        }
      }
    );