问题
Let's say I have this schema:
var UserSchema = new Schema({
name : {
firstName : String,
lastName : String
}
});
And I create this user:
User.create({
name : {
firstName : Bob,
lastName : Marley
}
}, function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
I noticed that if I do this:
User.findOneAndUpdate({_id: userId}, { name: { firstName : "Damian" } }, function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
My user now is:
user = {
name : {
firstName : "Damian"
}
}
However, if I do this:
User.findOneAndUpdate({_id: userId}, { "name.firstName" : "Damian" }, function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
My user is:
user = {
name : {
firstName : "Damian",
lastName : "Marley"
}
}
Is there a way to pass an Object with not all of its attributes filled out to findOneAndUpdate, and keep the attributes that were there before, without getting rid of them? (same functionality as $set in Mongo). This is really annoying...
回答1:
Flatten your incomplete nested object with flat, like this:
var flatten = require('flat')
flatten({
name : {
firstName : "Damian"
}
})
// {
// 'name.firstName': 'Damian'
// }
And now you can call findOneAndUpdate exactly as you did in your second example.
回答2:
If you pass actual full nested object to findOneAndUpdate() (or any other mongoose update method):
Model.findOneAndUpdate({ ... }, {
name: {
firstName : "Damian"
}
})
You will overwrite the whole (nested) object, therefore removing all of its other properties from the document (in this case: lastName).
To update only specific properties of the nested object, not the whole object, you need to use full path to the nested properties.
{ "name.firstName" : "Damian" }
(this will leave lastName in the nested name object untouched)
But it can be annoying to take care of that manually, whenever you update nested object's properties.
Luckily, it's not a problem at all to flatten the update object you pass to findOneAndUpdate() - so it never ends up being more than one level deep.
There are many ways to do this, debated upon in this question: Fastest way to flatten / un-flatten nested JSON objects .
The quickest solution seems to be to use ready-made flat Node.js library.
var flatten = require('flat')
User.findOneAndUpdate(
{ _id: userId },
// same as passing '{ "name.firstName": "Damian" }':
flatten({
name: {
firstName : "Damian"
}
}), function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
来源:https://stackoverflow.com/questions/30278445/findoneandupdate-overwriting-attributes-in-2-level-deep-object-passed-as-doc