user2010955
user2010955

Reputation: 4011

Javascript (ES6 + Lodash) merge source object with another updating only common properties, deeply

I have to deeply update an object with a provided one , keeping only the properties/paths found in the source object. I tried Lodash.merge, but it merges all the properties of the second object, I want to merge only the properties found in the source object.

Here is an example:

const ob1 = {
  a1: {
    b1: 2
  },
  a2: 5
}

const obj2 = {
  a1: {
    b1: 4,
    b2: 9
  },
  a3: 6
}

expected result = {
  a1: {
    b1: 4
  },
  a2: 5
}

I'd like the simplest solution with es6 or lodash utils.

Any ideas? Thanks!

Upvotes: 0

Views: 183

Answers (1)

Terry
Terry

Reputation: 66123

If you want a custom merge strategy, perhaps you can write your own recursive function. In the recursive function, you basically pass in your target and your source. Based on your question, the target will be obj1 and the source will be obj2.

Your logic is that:

  1. If obj1 does not contain a key that is in obj2, we keep the key-value pair from the obj1, the source
  2. If obj1 contains a key that is obj2, then:
    • If they are simply non-objects, we allow obj2 value to override obj1 value
    • If they are both objects, then we call the same recursive function again

See proof-of-concept below:

const obj1 = {
  a1: {
    b1: 2
  },
  a2: 5
}

const obj2 = {
  a1: {
    b1: 4,
    b2: 9
  },
  a3: 6
}

function smartMerge(target, source) {
  const o = {};
  
  // Iterate throught all keys in your target
  for(let k in target) {
  
    // If a matching key is found in source
    if (k in source) {
      // If they are both objects, then we run recurisve merge logic
      if (typeof target[k] === 'object' && typeof source[k] === 'object') {
        o[k] = smartMerge(target[k], source[k]);
      }
      // Otherwise, we let the source override the value
      else {
        o[k] = source[k];
      }
    }
    
    // If no matching key is found, we keep the target value
    else {
      o[k] = target[k];
    }
  }
  
  return o;
}

const result = smartMerge(obj1, obj2);

/* Expected:
{
  a1: {
    b1: 4
  },
  a2: 5
}
*/
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

Upvotes: 1

Related Questions