Mister_L
Mister_L

Reputation: 2621

mongoose - findOneAndUpdate with $set flag

Consider this command:

    WorkPlan.findOneAndUpdate({ _id: req.params.id }, updateObj, function(err) {
    ...
    })

versus this:

    WorkPlan.findOneAndUpdate({ _id: req.params.id }, { '$set': updateObj }, function(err) {
    ...
    })

While developing my project, I was surprised to find out that the result of the first command is the same as the result of the second command: the updateObj is merged into the existing record in the database, even in the first case when it is supposed to replace it. Is this a bug in mongoose/mongodb or am I doing something wrong? how can I replace an object on update instead of merging it? I'm using mongoose 4.0.7.

Thanks.

==========

Update:

This is the actual WorkPlan schema definition:

workPlanSchema = mongoose.Schema({
    planId: { type: String, required: true },
    projectName: { type: String, required: true },
    projectNumber: { type: String, required: false },
    projectManagerName: { type: String, required: true },
    clientPhoneNumber: { type: String, required: false },
    clientEmail: { type: String, required: true },
    projectEndShowDate: { type: Date, required: true },
    segmentationsToDisplay: { type: [String], required: false },
    areas: [
        {
          fatherArea: { type: mongoose.Schema.ObjectId, ref: 'Area' },
          childAreas: [{ childId : { type: mongoose.Schema.ObjectId, ref:   'Area' }, status: { type: String, default: 'none' } }]
        }
],
    logoPositions: [
                 {
                   lat: { type: Number, required: true },
                   lng: { type: Number, required: true }
                 }
    ],
    logoPath: { type: String, required: false },
    }, { collection: 'workPlans' });


WorkPlan = mongoose.model('WorkPlan', workPlanSchema);

And this is an example of updateObj:

    var updateObj = {
        projectManagerName: projectManagerName,
        clientEmail: clientEmail,
        clientPhoneNumber: clientPhoneNumber,
        segmentationsToDisplay: segmentationsToDisplay ? segmentationsToDisplay.split(',') : []
    }

Therefore, when I'm NOT using the $set flag, I would expect the field projectNumber, for example, not to exist in the new record, yet I see it is still there.

Upvotes: 10

Views: 23925

Answers (3)

Karunakaran
Karunakaran

Reputation: 435

This is works for me $set in Mongoose 5.10.1,

 WorkPlan.where({ _id: req.params.id }).updateOne(updateObj);

Note:if you have inner object then give exact path of each key in updateObj

example:

"Document.data.age" = 19

ref: https://mongoosejs.com/docs/api.html#query_Query-set

Upvotes: 0

PJately
PJately

Reputation: 477

In addition to the answer above:

[options.overwrite=false] «Boolean» By default, if you don't include any update operators in doc, Mongoose will wrap doc in $set for you. This prevents you from accidentally overwriting the document. This option tells Mongoose to skip adding $set.

Link to docs: https://mongoosejs.com/docs/api.html#model_Model.update

Upvotes: 0

axanpi
axanpi

Reputation: 731

Mongoose update treats all top level keys as $set operations (this is made more clear in the older docs: Mongoose 2.7.x update docs).

In order to get the behavior you want, you need to set the overwrite option to true:

WorkPlan.findOneAndUpdate({ _id: req.params.id }, updateObj, { overwrite: true }, function(err) {
    ...
})

See Mongoose Update documentation

Upvotes: 17

Related Questions