1

I have a couple of Objects with the same properties. I want to combine all of the object which has the same first level key-value. I am aware of the spread operator

    const obj3 = {...obj1, ...obj2}

but the problem is, the arrays inside the object are getting overwritten and not merged.

{
  "id": 1,
  "name": "firstLevel",
  "visible": true,
  "subCategories": [
    {
      "id": 2,
      "name": "secondLevel",
      "visible": true,
      "skills": [
        {
          "name": "foo",
          "id": 5,
          "visible": true
        }
      ]
    }
  ]
}
{
  "id": 1,
  "name": "firstLevel",
  "visible": true,
  "subCategories": [
    {
      "id": 2,
      "name": "secondLevel",
      "visible": true,
      "skills": [
        {
          "name": "bar",
          "id": 1,
          "visible": true
        }
      ]
    }
  ]
}

I expect the objects to combine like that :

{
  "id": 1,
  "name": "firstLevel",
  "visible": true,
  "subCategories": [
    {
      "id": 2,
      "name": "secondLevel",
      "visible": true,
      "skills": [
        {
          "name": "foo",
          "id": 5,
          "visible": true
        },
        {
          "name": "bar",
          "id": 1,
          "visible": true
        }
      ]
    }
  ]
}
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338

1 Answers1

2

You are looking for lodash.mergeWith, which merges arrays and plain object properties recursively.

var object = {
  'a': [{ 'b': 2 }, { 'd': 4 }]
};
 
var other = {
  'a': [{ 'c': 3 }, { 'e': 5 }]
};

function customizer(objValue, srcValue) {
  if (_.isArray(objValue)) {
    return objValue.concat(srcValue);
  }
}
 
_.mergeWith(object, other, customizer);
// => { 'a': [{ 'b': 2 }, { 'c': 3 }, { 'd': 4 }, { 'e': 5 }] }

For your particular case when you know the ids of the objects, this customizer function will work as requested.

function customizer(objValue, srcValue) {
  if (_.isArray(objValue)) {
    for (const srcItem of srcValue) {
      const objItem = objValue.filter(item => item.id === srcItem.id);
      if (objItem.length) {
        objValue = objValue.map(item => {
          if (item.id === objItem[0].id) {
            return _.mergeWith(item, srcItem, customizer);
          }

          return item;
        });
      } else {
        objValue = [...objValue, srcItem];
      }
    }

    return objValue;
  }
}
Valdrinium
  • 1,398
  • 1
  • 13
  • 28