Skip to content Skip to sidebar Skip to footer

How To Update Multiple Fields Of An Array Object With One Request?

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

Solution 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.


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

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

Post a Comment for "How To Update Multiple Fields Of An Array Object With One Request?"