如何用一个请求更新数组对象的多个字段?

{ _id:xxxxstoreid store:{ products:[ { _id:xxxproductid, name:xxx, img:url, } ] } } 

因为我无法预测更新的请求,params可能只是名称,或者它可能同时具有。

这里是我的查询,它更新成功,但它会删除其他字段,如果它们不在PARAMS中。 例如:

 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 ,以更新两个匹配的键。

我更喜欢现代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'}},{})

基本上你把你的inputparams并提供_id作为“查询”的第一个参数:

  { 'store.products._id': params._id }, 

剩下的就是通过Object.keys从对象中获取“keys”,这个“Array”我们可以使用Array.filter()来“过滤”,然后传递给Array.reduce把这些键转换成一个Object

.reduce()内部,我们调用Object.assign() ,它将“合并”对象与给定的关键字,并以这种forms生成:

  Object.assign(acc,{ [`store.products.$.${curr}`]: params[curr] }), 

使用模板语法将“当前”(curr)“键”分配到新的键名中,再次使用ES6键分配语法[]:它允许对象文字中的variables名。

生成的“合并”对象被传递回被分配给“root”对象,其中$set被用于更新的关键字,所以“生成”关键字现在是该对象的子对象。

我纯粹为debugging目的使用一个数组作为参数,但是这样也可以使用“spread” ...运算符来分配参数,从而在实际的.update()上允许使用更清晰的语法:

 User.update(...update,callback); 

干净,简单,以及一些JavaScript技术,你应该学习对象和数组操作。 主要是因为MongoDB查询DSL基本上是“对象”和“arrays”。 所以学会操纵它们。

 function updateProducts(params) { var query = {'store.products': {$elemMatch: {_id: params._id}}} var updateObject = null; if (params.name && params.img) { updateObject = {$set: {'store.products.$': params}} } else if(params.name && !params.img) { updateObject = {$set: {'store.products.$.name': params.name}} } else if (params.img && !params.name) { updateObject = {$set: {'store.products.$.img': params.img}} } User.update(query, updateObject, callback) } 

下面的查询将使用$位置运算符来查找在查询文档中通过_id匹配数组所find的索引处的数组元素,然后使用params值更新该元素的字段。

 var params = {_id:1, name:'xxx',img:'yyy'}; var id = params['_id']; // Get id to locate matching array index delete params['_id']; // Remove id from the object Object.keys(params).forEach(function (key){params['store.products.$.'+key] = params[key]; delete params[key];}) // Transforms remaining object keys to include the positional $ placeholder to { "store.products.$.name" : "xxx", "store.products.$.img" : "yyy" } User.update('store.products._id':id},{$set:params},callback);