How to update multiple fields of an array object with one request?

北城以北 提交于 2020-01-30 09:06:15

问题


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

since i cannot predict the request for update, params may have just name or it may have both.

here is my query,it updates successfully but it removes other fields if they are not present in the params. eg:

var params={_id:xxid,name:'xxx',img:'xxx'}

or

var params={_id:xxid,name:'xxx'}

in this case if params have just name it removes img field and updates.

User.update({'store.products._id':params._id},{$set:{"store.products":params}},callback);

回答1:


You need to supply the multiple keys to $set with the positional $ operator to update both matched keys.

I prefer the modern ES6 way of object manipulation:

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);

Which would produce the call to MongoDB as ( with mongoose.set('debug', true) ) turned on so we see the request:

Mongoose: users.update({ 'store.products._id': 'xxxproductid' }, { '$set': { 'store.products.$.name': 'xxx', 'store.products.$.img': 'yyy' } }, {})

Where basically you take your input params and supply the _id as the first argument for the "query" :

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

The rest takes the "keys" from the object via Object.keys which makes an "array" which we can "filter" with Array.filter() and then pass to Array.reduce to transform those keys into an Object.

Inside the .reduce() we call Object.assign() which "merges" objects with the given keys, generated in this form:

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

Using the template syntax to assign the "current" (curr) "key" into the new key name, again using the ES6 key assignment syntax []: which allows variable names in object literals.

The resulting "merged" object is passed back to be assigned to the "root" object where $set is used for the key of the update, so the "generated" keys are now children of that.

I use an array for the arguments purely for debugging purposes, but then that also allows cleaner syntax on the actual .update() using the "spread" ... operator to assign the arguments:

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

Clean and simple, and some JavaScript techniques that you should learn for object and array manipulation. Mostly since the MongoDB query DSL is basically "Objects" and "Arrays". So learn to manipulate them.




回答2:


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)
}



回答3:


The below query will use $ positional operator to locate the array element at index found from matching the array by _id in the query document followed by updating the fields for the element with the params values.

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);


来源:https://stackoverflow.com/questions/44850822/how-to-update-multiple-fields-of-an-array-object-with-one-request

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!