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
Post a Comment