Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

110
Views
Update a JavaScript object recursively using values from another object

I would like to add some data to a nested JavaScript object, however I do not know how much of the object tree already exists. I want to add the structure if it is not there, but also keep the same information if it is there tagged with some other default data.

Ideally I don't want to use a third party library for this.

In my example I have the following object structure, there will be an endless combination of these available, so it needs to generate the structure for me if it does not already exist.

{
  level1: {
    level2: {
      level3: {
        property1: 'test'
      }
    }
  }
}

I want to be able give this some values, create the structure - if the structure is there, add some default values and if not create the structure with defaults.

I have the following, which does the job, but it looks very messy to me, I was wondering if there was a better way to achieve this?

const updateNestedObject = (obj, level1, level2, level3, defaultProps) => {
  if (obj && obj[level1] && obj[level1][level2] && obj[level1][level2][level3]) {
    obj[level1][level2][level3] = { ...defaultProps, ...obj[level1][level2][level3] }
  } else if (obj && obj[level1] && obj[level1][level2] && !obj[level1][level2][level3]) {
    obj[level1][level2][level3] = defaultProps
  } else if (obj && obj[level1] && !obj[level1][level2]) { 
    obj[level1][level2] = { [level3]: defaultProps }
  } else if (obj && !obj[level1]) { 
    obj[level1] = { [level2]: { [level3]: defaultProps } }
  } else {
    obj = { [level1]: { [level2]: { [level3]: defaultProps } } }
  }
  return obj
}
about 4 years ago · Juan Pablo Isaza
3 answers
Answer question

0

You could do something like this, where you loop over the keys and traverse the object level by level. Each loop we set an outside variable - level - to the current one, so we don't have to use the previous keys to reach the current level. i.e., we avoid having to do obj[ level1 ][ level2 ][ level3 ] = ..., instead, we can just do level = ...

In this way, I'd say it's better to pass a single parameter keys, which is an array. With this, you aren't limited to exactly 3 nested keys, but can pass any number you want to.

const updateNestedObject = ( obj, keys, defaultProps ) => {
  let level = obj;
  for ( let i = 0; i <= keys.length-1; i++ ) {
    let key = keys[ i ];

    if ( i === keys.length-1 ) {
      level[ key ] = { ...defaultProps };
      return;
    }

    if ( !level[ key ] ) {
      level[ key ] = {};
    }

    level = level[ key ];
  }
};

const object = {};
updateNestedObject( object, [ "foo", "bar", "baz" ], { property: "test" } )
console.log( object );

const object2 = { foo: { bar: {} } };
updateNestedObject( object2, [ "foo", "bar", "baz" ], { property: "test" } )
console.log( object2 );

const object3 = { foo: { bar: {} } };
updateNestedObject( object3, [ "foo", "bar" ], { property: "test" } )
console.log( object3 );

Note that this does change the object in-place.

about 4 years ago · Juan Pablo Isaza Report

0

This could be done via recursion. Below is an outline of how to implement it (not tested for all cases):

function mergeRecursive(targetObject, sourceObject) {
  Object.keys(sourceObject).forEach(function(key) {
    if (typeof sourceObject[key] === "object") {
      if (targetObject[key] === undefined) {
        targetObject[key] = {};
      }
      mergeRecursive(targetObject[key], sourceObject[key]);
    } else {
      targetObject[key] = sourceObject[key];
    }
  });
}
let foo = {
  "level1": {
    "bar": "baz"
  }
};
let bar = {
  level1: {
    level2: {
      level3: {
        property1: "test"
      }
    }
  }
};
mergeRecursive(foo, bar);
console.log(foo);

about 4 years ago · Juan Pablo Isaza Report

0

A minor variant of a setPath function I use often would do this in a fairly straightforward manner:

const mixDeep = ([p, ...ps]) => (v) => (o) =>
  p == undefined ? v : Object .assign (
    Array .isArray (o) || Number .isInteger (p) ? [] : {},
    {...o, [p]: ps .length ? mixDeep (ps) (v) ((o || {}) [p]) : {...v, ...(o || {}) [p]}},
  ) 

const myFunc = 
  mixDeep (['level1', 'level2', 'level3']) ({some: 'default', props: 'here'}) 

console .log (myFunc ({foo: 'bar'}))
console .log (myFunc ({foo: 'bar', level1: {baz: 'qux'}}))
console .log (myFunc ({foo: 'bar', level1: {baz: 'qux', level2: {corge: 'grault'}}}))
console .log (myFunc ({foo: 'bar', level1: {baz: 'qux', level2: {corge: 'grault', level3: {garply: 'waldo'}}}}))
.as-console-wrapper {max-height: 100% !important; top: 0}

setPath sets the value at the path, building intermediate nodes as necessary. mixDeep mixes the value into the value at the end of the path, again building whatever intermediate nodes are missing.

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!