最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to update multiple fields of an array object with one request? - Stack Overflow

programmeradmin2浏览0评论
{
   _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);
{
   _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);
Share Improve this question edited Jul 1, 2017 at 5:43 Madhvesh S asked Jun 30, 2017 at 16:11 Madhvesh SMadhvesh S 13912 bronze badges 0
Add a ment  | 

3 Answers 3

Reset to default 5

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.

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

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);
发布评论

评论列表(0)

  1. 暂无评论