Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursively update nested object values for specific keys based on another object

*** UPDATED object structure ***

I'd like to update recursively the property values of mainObject from the properties that exist in updatingObject.

let mainObject = {
  age: 24,
  isMarried: false,
  pets: {
    dog: {
      name: "Juniper",
      age: 3
    },
    cat: {
      name: "Spasia",
      age: 7
    }
 },
 hobbies: {
    mountainRelated: ["hiking", "snowboarding"]
 }
}

let updatingObject = {
   pets: {
      cat: {
         age: 8
      }
   }
}

I've added a Codepen link to the problem below: what I still have to do is to find the correct properties to be updated (for example the "age" property is common for more objects).

TL;DR: cat age should be 8 in the mainObject

https://codepen.io/Dragosb/pen/bGwypKz?editors=0012

like image 610
DragosB Avatar asked Jun 05 '26 00:06

DragosB


2 Answers

You can traverse in sync

let mainObject = {
  age: 24,
  isMarried: false,
  pets: {
    dog: { name: "Juniper", age: 3 },
    cat: { name: "Spasia", age: 7 }
 },
 hobbies: {
    mountainRelated: ["hiking", "snowboarding"]
 }
}

let updatingObject = {
   pets: {
      cat: {
         age: 8,
name:'gabriele'
      }
   }
}


function updateObject(target, update){
   // for each key/value pair in update object
   for (const [key,value] of Object.entries(update)){
      // if target has the relevant key and
      // the type in target and update is the same
      if (target.hasOwnProperty(key) && typeof(value) === typeof(target[key])){
        // update value if string,number or boolean
        if (['string','number','boolean'].includes(typeof value) || Array.isArray(value)){
          target[key] = value;
        } else {
          // if type is object then go one level deeper
          if (typeof value === 'object'){
             updateObject(target[key], value)
          }
        }
      }
   }
}

updateObject(mainObject,updatingObject)
console.log(mainObject);
like image 145
Gabriele Petrioli Avatar answered Jun 07 '26 12:06

Gabriele Petrioli


We can write a function that does this without mutating the original object, in a fairly simple manner. This merge function breaks the original and update objects into key-value pairs, then keeps all those whose keys are only in one of them, and, for those in both, if both values are objects recursively calling merge on them, otherwise choosing the update value. The resulting key-value pairs are then put back into an object.

Here is an implementation:

const merge = (a, b) => Object .fromEntries ([
  ... Object .entries (a) .filter (([k]) => !(k in b)),
  ... Object .entries (b) .filter (([k]) => !(k in a)),
  ... Object. entries (b) .filter (([k]) => (k in a)) .map (([k, v]) => 
        [k, Object (v) === v && Object (a [k]) === a [k] ? merge (a [k], v) : v]
      ),
])


const mainObject = {age: 24, isMarried: false, pets: {dog: { name: "Juniper", age: 3 }, cat: { name: "Spasia", age: 7 }}, hobbies: {mountainRelated: ["hiking", "snowboarding"]}}
const updatingObject = {pets: {cat: {age: 8, name:'gabriele'}}}


console .log (merge (mainObject, updatingObject))
.as-console-wrapper {max-height: 100% !important; top: 0}

Note that while the resulting object is a new one, we use a form of structural sharing between this and the input objects. For instance, if you push 'hangliding' onto the array hobbies.mountainRelated in the resulting object, we will update mainObject values as well. While we could change this behavior, it helps reduce memory consumption, so I wouldn't do so without good reason.

Note that this does not try to deal with more complicated scenarios, such as cyclic objects. It also does not do anything to work with arrays. Arrays add numerous complexities, and if you need them, I would suggest looking at the equivalent functions in a library such as Ramda's mergeDeepRight (disclaimer: I'm an author) or lodash's merge, or dedicated tools like deepmerge.

like image 31
Scott Sauyet Avatar answered Jun 07 '26 14:06

Scott Sauyet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!