findOneAndUpdate 覆盖作为 doc 传递的 2+ 级深度对象中的属性
findOneAndUpdate overwriting attributes in 2+ level deep object passed as doc
假设我有这个架构:
var UserSchema = new Schema({
name : {
firstName : String,
lastName : String
}
});
然后我创建了这个用户:
User.create({
name : {
firstName : Bob,
lastName : Marley
}
}, function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
我注意到如果我这样做:
User.findOneAndUpdate({_id: userId}, { name: { firstName : "Damian" } }, function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
我现在的用户是:
user = {
name : {
firstName : "Damian"
}
}
但是,如果我这样做:
User.findOneAndUpdate({_id: userId}, { "name.firstName" : "Damian" }, function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
我的用户是:
user = {
name : {
firstName : "Damian",
lastName : "Marley"
}
}
有没有办法将一个未填写所有属性的对象传递给 findOneAndUpdate
,并保留之前存在的属性,而不删除它们? (与 Mongo 中的 $set
功能相同)。这真的很烦人...
用 flat 拼合不完整的嵌套对象,如下所示:
var flatten = require('flat')
flatten({
name : {
firstName : "Damian"
}
})
// {
// 'name.firstName': 'Damian'
// }
现在您可以像在第二个示例中那样调用 findOneAndUpdate
。
如果将实际的完整嵌套对象传递给 findOneAndUpdate()
(或任何其他 mongoose
更新方法):
Model.findOneAndUpdate({ ... }, {
name: {
firstName : "Damian"
}
})
您将覆盖整个(嵌套)对象,因此从文档中删除其所有其他属性(在本例中:lastName
)。
要仅更新嵌套对象的特定属性,而不是 整个 对象,您需要使用嵌套属性的完整路径。
{ "name.firstName" : "Damian" }
(这将使嵌套的 name
对象中的 lastName
保持不变)
但是,每当您更新嵌套对象的属性时,手动处理它可能会很烦人。
幸运的是,扁平化 传递给 findOneAndUpdate()
的更新对象完全不是问题 - 所以它永远不会超过一层深度。
有很多方法可以做到这一点,在这个问题中进行了辩论:Fastest way to flatten / un-flatten nested JSON objects .
最快的解决方案似乎是使用现成的 flat
Node.js 库。
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);
}
});
假设我有这个架构:
var UserSchema = new Schema({
name : {
firstName : String,
lastName : String
}
});
然后我创建了这个用户:
User.create({
name : {
firstName : Bob,
lastName : Marley
}
}, function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
我注意到如果我这样做:
User.findOneAndUpdate({_id: userId}, { name: { firstName : "Damian" } }, function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
我现在的用户是:
user = {
name : {
firstName : "Damian"
}
}
但是,如果我这样做:
User.findOneAndUpdate({_id: userId}, { "name.firstName" : "Damian" }, function (err, user) {
if(err) {
return console.error(err);
} else {
return console.log(user);
}
});
我的用户是:
user = {
name : {
firstName : "Damian",
lastName : "Marley"
}
}
有没有办法将一个未填写所有属性的对象传递给 findOneAndUpdate
,并保留之前存在的属性,而不删除它们? (与 Mongo 中的 $set
功能相同)。这真的很烦人...
用 flat 拼合不完整的嵌套对象,如下所示:
var flatten = require('flat')
flatten({
name : {
firstName : "Damian"
}
})
// {
// 'name.firstName': 'Damian'
// }
现在您可以像在第二个示例中那样调用 findOneAndUpdate
。
如果将实际的完整嵌套对象传递给 findOneAndUpdate()
(或任何其他 mongoose
更新方法):
Model.findOneAndUpdate({ ... }, {
name: {
firstName : "Damian"
}
})
您将覆盖整个(嵌套)对象,因此从文档中删除其所有其他属性(在本例中:lastName
)。
要仅更新嵌套对象的特定属性,而不是 整个 对象,您需要使用嵌套属性的完整路径。
{ "name.firstName" : "Damian" }
(这将使嵌套的 name
对象中的 lastName
保持不变)
但是,每当您更新嵌套对象的属性时,手动处理它可能会很烦人。
幸运的是,扁平化 传递给 findOneAndUpdate()
的更新对象完全不是问题 - 所以它永远不会超过一层深度。
有很多方法可以做到这一点,在这个问题中进行了辩论:Fastest way to flatten / un-flatten nested JSON objects .
最快的解决方案似乎是使用现成的 flat
Node.js 库。
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);
}
});