{
_id:xxxxstoreid
store:{
products:[
{
_id:xxxproductid,
name:xxx,
img:url,
}
]
}
}
由于我无法预测更新请求,参数可能只有名称,也可能两者都有。
这是我的查询,它更新成功,但如果参数中不存在其他字段,它会删除它们。 例如:
var params={_id:xxid,name:'xxx',img:'xxx'}
或
var params={_id:xxid,name:'xxx'}
在这种情况下,如果参数只有名称,它将删除 img 字段并更新。
User.update({'store.products._id':params._id},{$set:{"store.products":params}},callback);
最佳答案
您需要向 $set
提供多个 key 与 positional $
operator更新两个匹配的 key 。
我更喜欢现代 ES6 的对象操作方式:
let params = { "_id" : "xxxproductid", "name" : "xxx", "img" : "yyy" };
let update = [
{ 'store.products._id': params._id },
{ "$set": Object.keys(params).filter(k => k != '_id')
.reduce((acc,curr) =>
Object.assign(acc,{ [`store.products.$.${curr}`]: params[curr] }),
{ })
}
];
User.update(...update,callback);
这将产生对 MongoDB 的调用(打开 mongoose.set('debug', true)
),以便我们看到请求:
Mongoose: users.update({ 'store.products._id': 'xxxproductid' }, { '$set': { 'store.products.$.name': 'xxx', 'store.products.$.img': 'yyy' } }, {})
基本上,您获取输入params
并提供_id
作为“查询”的第一个参数:
{ 'store.products._id': params._id },
其余部分通过 Object.keys
从对象获取“键”这使得我们可以用 Array.filter()
“过滤”一个“数组”然后传递给Array.reduce
将这些键转换为对象
。
.reduce()
内我们调用Object.assign()
它将对象与给定的键“合并”,以这种形式生成:
Object.assign(acc,{ [`store.products.$.${curr}`]: params[curr] }),
使用模板语法将“当前”(curr)“键”分配给新键名称,再次使用 ES6 key assignment syntax []:
它允许对象文字中的变量名称。
生成的“合并”对象被传回并分配给“根”对象,其中 $set
用于更新的 key ,因此“生成”的 key 现在是那个。
我使用数组作为参数纯粹是为了调试目的,但这也允许使用“spread”...
在实际的.update()
上使用更清晰的语法。 > 运算符来分配参数:
User.update(...update,callback);
干净、简单,以及一些您应该学习的用于对象和数组操作的 JavaScript 技术。主要是因为 MongoDB 查询 DSL 基本上是“对象”和“数组”。所以要学会操纵它们。
关于javascript - 如何通过一个请求更新数组对象的多个字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58670308/