Reputation: 2621
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
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
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
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