2

I have two deeply nested objects containing arrays and objects within those arrays. I'd like to merge those. Using 'lodash' it doesn't recognize my objects within arrays.

I have this:

var defaults = {
    rooms: [
        {
            name: 'livingroom',
            color: 'white'
        },
        {
            name: 'bedroom',
            color: 'red'
        }
    ],
    people: {
        clothes: [
            {
                fabric: 'wool',
                color: 'black'
            },
            {
                fabric: 'jeans',
                color: 'blue'
            }
        ]
    }
}

var specific = {
    people: {
        wigs: [
            {
                shape: 'trump'
            }
        ]
    },
    furniture : {
        foo: 'bar'
    }
}

the result should look like this:

var merged = {
    rooms: [
        {
            name: 'livingroom',
            color: 'white'
        },
        {
            name: 'bedroom',
            color: 'red'
        }
    ],
    people: {
        clothes: [
            {
                fabric: 'wool',
                color: 'black'
            },
            {
                fabric: 'jeans',
                color: 'blue'
            }
        ],
        wigs: [
            {
                shape: 'trump'
            }
        ]
    },
    furniture : {
        foo: 'bar'
    }
}

using lodash

const _ = require('lodash');
console.log(_.merge({}, specific, defaults));

i get

{ people: { wigs: [ [Object] ], clothes: [ [Object], [Object] ] },
  furniture: { foo: 'bar' },
  rooms:
   [ { name: 'livingroom', color: 'white' },
     { name: 'bedroom', color: 'red' } ] }

this is related to:

Merge Array of Objects by Property using Lodash

How to merge two arrays in JavaScript and de-duplicate items

because I don't have a common index or name I'm a bit lost.

Simon
  • 354
  • 3
  • 10
  • do you need to keep the object, or is it ok to mutate the objects? – Nina Scholz Mar 01 '19 at 11:09
  • no need to keep it. Mutation is fine. – Simon Mar 01 '19 at 11:15
  • Lodash's `_.merge()` works for your case - https://jsfiddle.net/py4h830d/ . Look at the brower's console. – Ori Drori Mar 01 '19 at 11:16
  • [How to deep merge instead of shallow merge?](https://stackoverflow.com/questions/27936772) – adiga Mar 01 '19 at 11:16
  • OriDrori you're right. I'm still new to js and had (only) issues with console.log() :-) However I like the Answer from Nina Scholz as it doesn't require lodash. I hope that's fine if I accept her answer :) – Simon Mar 01 '19 at 12:26

1 Answers1

2

You could merge specific to defaults by looking at object or arrays.

function merge(a, b) {
    Object.keys(b).forEach(k => {
        if (!(k in a)) {
            a[k] = b[k];
            return;
        }
        if ([a, b].every(o => o[k] && typeof o[k] === 'object' && !Array.isArray(o[k]))) {
            merge(a[k], b[k]);
            return;
        }
        if (!Array.isArray(a[k])) a[k] = [a[k]];
        a[k] = a[k].concat(b[k]);
    });
    return a;
}

var defaults = { rooms: [{ name: 'livingroom', color: 'white' }, { name: 'bedroom', color: 'red' }], people: { clothes: [{ fabric: 'wool', color: 'black' }, { fabric: 'jeans', color: 'blue' }] } },
    specific = { people: { wigs: [{ shape: 'trump' }] }, furniture: { foo: 'bar' } };

[defaults, specific].reduce(merge);

console.log(defaults);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392