node.js - findByIdAndUpdate With Multiple Subdocuments -


so i'm working nodejs , mongodb, , i'm making endpoint lets clients update user profiles several optional data fields. so, 1 of update queries can this:

{      name: { givenname: 'first' },     about: 'whatever',     auth: { password: 'hashedpw' }  } 

the mongoose api docs state following info findbyidandupdate: top level update keys not atomic operation names treated set operations.

so top level key, about, works fine update. however, nested keys, name , auth overwritten update values, rather having values set.

now go through , manually change each of fields $set key, there lot of different fields, pretty annoying. there easy way apply $set rule subdocuments well? i.e. transform statement this, mongoose option or something:

{      $set : { name: { givenname: 'first' } },     $set : { about: 'whatever' },     $set : { auth: { password: 'hashedpw' } }  } 

you need tranform input object "dot notation" form in order avoid overwring other possible sub-keys in update. quite simple really:

var obj = {      name: { givenname: 'first' },     about: 'whatever',     auth: { password: 'hashedpw' }  };  var target = {};  function dotnotate(obj,prefix) {   prefix = (typeof(prefix) === 'undefined') ? "" : prefix;   object.keys(obj).foreach(function(key) {     if ( typeof(obj[key]) === "object" ) {       dotnotate(obj[key],key + ".")     } else {       target[prefix + key] = obj[key];     }   }); }  dotnotate(obj); 

now target object looks this:

{     "name.givenname" : "first",     "about" : "whatever",     "auth.password" : "hashedpw" } 

so update block of statement merely written as:

{ "$set": target } 

for reference, dotnotate() function can bit more refined , self contained. including shorter default assignments valid input considered "truthy". "prefix" should have been pre-pended on each call make work @ arbitrary depth:

function dotnotate(obj,target,prefix) {   target = target || {},   prefix = prefix || "";    object.keys(obj).foreach(function(key) {     if ( typeof(obj[key]) === "object" ) {       dotnotate(obj[key],target,prefix + key + ".");     } else {       return target[prefix + key] = obj[key];     }   });    return target; } 

then can use either inline:

var update = { "$set": dotnotate(obj) }; 

or pass in defined object if prefer:

var update = { "$set": {} }; dotnotate(obj,update["$set"]); 

with same results.

also fine arrays , nested depth:

{     "things" : [         {             "a" : 1,             "b" : 2         },         {             "a" : 3,             "b" : 4         }     ],     "bool" : false } 

with output:

{     "things.0.a" : 1,     "things.0.b" : 2,     "things.1.a" : 3,     "things.1.b" : 4,     "bool" : false } 

Comments

Popular posts from this blog

php - Admin SDK -- get information about the group -

dns - How To Use Custom Nameserver On Free Cloudflare? -

Python Error - TypeError: input expected at most 1 arguments, got 3 -