我有这样的架构:
this.schema = new Schema({
userEmail: String
environments: [
{
envId: String,
appPreference: String,
language: String,
timeZone: String,
summaryNotificationSchedule: {
timeOfTheDay: String
}
}
]
});
更新请求:
{
"envId": "u2",
"appPreference": "put2",
"timeZone": "gmt",
"summaryNotificationSchedule.timeOfTheDay": "32400",
}
如您所见,我没有在更新请求中发送 "language": "abc",
,结果我看到language
字段已删除。我想更新字段,但不删除其他字段
猫鼬查找和更新呼叫:
await this.model.findOneAndUpdate({ userEmail, 'environments.envId': envId }, { $set: { 'environments.$': setPreferenceFields } }, { new: true });
答案 0 :(得分:2)
您可以先根据请求创建更新对象:
let request = {
"envId": "u2",
"appPreference": "put2",
"timeZone": "gmt",
"summaryNotificationSchedule.timeOfTheDay": "32400",
};
let update = Object.keys(request).reduce((acc, cur) => {
acc[`environments.$.${cur}`] = request[cur];
return acc;
}, {})
console.log(update);
然后将其传递给更新:
await this.model.findOneAndUpdate({ userEmail, 'environments.envId': envId }, { $set: update }, { new: true });
答案 1 :(得分:1)
您必须使用数组的父键名称指定属性,就像这样,
await this.model.findOneAndUpdate(
{
userEmail,
'environments.envId': envId
},
{
$set: {
'environments.$.envId': "u2",
'environments.$.appPreference': "put2",
'environments.$.timeZone': "gmt",
'environments.$.summaryNotificationSchedule.timeOfTheDay': "32400"
}
},
{ new: true }
)
另一个选择update with aggregation pipeline从MongoDB v4.2开始,这个过程比上面的方法要花点时间,
$map
迭代environments
数组循环$cond
检查条件,如果envId
等于匹配的envId,然后使用$mergeObjects
合并对象更新对象和当前对象,否则返回当前对象await this.model.findOneAndUpdate(
{ userEmail },
[
{
$set: {
environments: {
$map: {
input: "$environments",
in: {
$cond: [
{$eq: ["$$this.envId", envId]}, // add update id
{
$mergeObjects: [
"$$this",
setPreferenceFields // your update fields
]
},
"$$this"
]
}
}
}
}
}
],
{new: true}
)