0

I want to deep merge 2 javascript objects with similar properties in a reducer. The catch is the two objects have arrays as their properties and I need them to be concatenated instead of replaced. Basically something like this:

var x = {
  name: 'abc',
  family: {
    children: [
      {name: 'xxx'},
      {name: 'zzz'}
    ]
  }
};

var y = {
  name: 'abc',
  family: {
    children: [
      {name: 'yyy'}
    ]
  }
};

will result on

var y = {
  name: 'abc',
    family: {
      children: [
        {name: 'xxx'}, {name: 'zzz'}, {name: 'yyy'}
      ]
    }
  };

any suggestion? I prefer lodash based solution if possible. Also, since it's in reducer, I cannot just replace the property with new object

2
  • what if x and y objects would have different name property value on the parent level? Commented Jan 26, 2017 at 8:36
  • in my specific case name can be replaced with source objects Commented Jan 26, 2017 at 8:41

3 Answers 3

0

objects have arrays as their properties and I need them to be concatenated instead of replaced

For your simple example it would be enough to use Array.prototype.concat() function:

var x = {name: 'abc', family:{children:[{name: 'xxx'}, {name: 'zzz'} ] }}, y = {name: 'abc', family: {children: [{name: 'yyy'}]}};

y.family.children = y.family.children.concat(x.family.children);
console.log(y);

Sign up to request clarification or add additional context in comments.

2 Comments

as I mentioned, I used this in reducer, so I cannot change property in y. I need to replace it with whole object, hence the merge process
@DanielW, why don't you post that reducer ?
0

If you're already using lodash, check if mergeWith doesn't do what you want... (see this so answer for example).

Anyway here is a quick function that should do what you want. Be warned that it does very little in terms of checking, and only merges properties that are in the first object (since you said that your objects are similar).

Also it doesn't mutate the objects but instead creates a new one.

function merge(a, b){
  var ret = {};
  for(prop in a){ 
    //assume b doesn't have properties that a hasn't
    //only merge on similar types, else keep a
    var propA = a[prop],
        propB = b[prop];
    console.log(prop, typeof propA)
    if( (typeof propA == typeof propB) && (typeof propA == "object")){
      if(Array.isArray(propA)){
        ret[prop] = propA.concat(propB);
      }else{
        ret[prop] = merge(propA, propB);
      }
    }else{
      ret[prop] = propA;
    }
  }
  return ret;
}
var x = {
  name: 'abc',
  family: {
    children: [
      {name: 'xxx'},
      {name: 'zzz'}
    ]
  }
};

var y = {
  name: 'abc',
  family: {
    children: [
      {name: 'yyy'}
    ]
  }
};

console.log(merge(x, y));
console.log(merge(y, x));

Comments

0

I assume one of your objects is the state you want to change in your reducer.

What about:

return Object.assign({}, x, {
   family: [...x.family, ...y.family]
  })

First this creates a new empty object and assigns x ( your old state ) to it. Afterwards it assigns the family which it overrides in the new object. The ... represents all elements in an array, so this can be used to concat the arrays.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.