Taichi
Taichi

Reputation: 2587

How to merge Object values of two Objects

I have two Object like this and want to merge them:

const obj1 = {
  1: { foo: 1 },
  2: { bar: 2, fooBar: 3 },
  3: { fooBar: 3 },
};

const obj2 = {
  1: { foo: 1, bar: 2 },
  2: { bar: 2 },
};

const merged = someMergingMethod(obj1, obj2);

merged === {
  1: { foo: 1, bar: 2 },
  2: { bar: 2, fooBar: 3 },
  3: { fooBar: 3 },
};

I mean, I want to not only merge the objects, but also merge their object values' properties too if the key is duplicated. Because just merged = { ...obj1, ...obj2 }; overwrites the properties with obj2's.

What is the easiest way to do this?

I can use ES2017 and other libraries like lodash.

Upvotes: 3

Views: 4950

Answers (6)

Rodrigo Rodrigues
Rodrigo Rodrigues

Reputation: 8556

This can be easily accomplished with a combination of the neat javascript spread syntax, Array and Object prototype functions, and destructuring patterns.

[obj1,obj2].flatMap(Object.entries).reduce((o,[k,v])=>({...o,[k]:{...o[k],...v}}),{})

As simple as this!


For a very detailed explanation of how this works, refer to this extended answer to a similar question.

Upvotes: 0

Shashidhar Reddy
Shashidhar Reddy

Reputation: 305

Are you looking like this?

we can use this way to merge two objects.

const person = { name: 'David Walsh', gender: 'Male' };
const attributes = { handsomeness: 'Extreme', hair: 'Brown', eyes: 'Blue' };
const summary = {...person, ...attributes};

/*

Object {
  "eyes": "Blue",
  "gender": "Male",
  "hair": "Brown",
  "handsomeness": "Extreme",
  "name": "David Walsh",
}

*/

Upvotes: 0

Rohit Jaiswal
Rohit Jaiswal

Reputation: 287

you can use Object.assign and and assign object properties to empty object.

var a =  {books: 2};
var b = {notebooks: 1};
var c = Object.assign( {}, a, b );
console.log(c);

or

You could use merge method from Lodash library. can check here : https://www.npmjs.com/package/lodash

Upvotes: 0

madhur acharya
madhur acharya

Reputation: 29

I have exactly what you want. This function will traverse through each nested object and combine it with the other. I've only tested it with 5 nested levels down the tree but, theoretically, it should work for any number of nested objects as it is a recursive function.

//this function is similar to object.assign but,
//leaves the keys which are common among both bojects untouched
function merge(object1, object2)
{
    function combine(p, q)
    {
        for(i in q)
            if(!p.hasOwnProperty(i))
                p[i]= q[i];
        return p;
    }
    obj1= Object.assign(combine(obj1, obj2), obj1);//for the first level 
    obj1= Object.assign(traverse(obj1, obj2), obj1);//for subsequent levels down theobjectt tree

//this function traverses each nested boject and combines it with the other object
    function traverse(a, b)
    {
        if(typeof(a) === "object" && typeof(b) === "object")
            for(i in b)
                if(typeof(a[i]) === "object" && typeof(b[i]) === "object")
                    a[i]= Object.assign(traverse(a[i], b[i]), a[i]);
                else
                    Object.assign(combine(a, b), a);
        return a;
    }
    return obj1;
}

console.log(merge(obj1, obj2));

Here is a working example of a much more complex object merging

var obj1 = {
  1: { foo: 1 },
  2: { bar: 2, fooBar: 3 },
  3: { fooBar: 3, boor:{foob: 1, foof: 8} },
  4: {continent: {
  		asia: {country: {india: {capital: "delhi"}, china: {capital: "beiging"}}},
  		europe:{country:{germany: {capital: "berlin"},france: {capital: "paris"}}}
  	},
  	vegtables: {cucumber: 2, carrot: 3, radish: 7}
  }
};

var obj2 = {
  1: { foo: 1, bar: 2 },
  2: { bar: 2 },
  3: {fooBar: 3, boor:{foob: 1, boof: 6}, boob: 9 },
  4: {continent: {
  		northamerica: {country: {mexico: {capital: "mexico city"}, canada: {capital: "ottawa"}},},
  		asia: {country: {Afghanistan : {capital: "Kabul"}}}
  	}
  },
  5: {barf: 42}
};

//this function is similar to object.assign but,
//leaves the keys which are common among both bojects untouched
function merge(object1, object2)
{
	function combine(p, q)
	{
		for(i in q)
			if(!p.hasOwnProperty(i))
				p[i]= q[i];
		return p;
	}
	obj1= Object.assign(combine(obj1, obj2), obj1);//for the first level 
	obj1= Object.assign(traverse(obj1, obj2), obj1);//for subsequent levels down the object tree

//this function traverses each nested boject and combines it with the other object
	function traverse(a, b)
	{
		if(typeof(a) === "object" && typeof(b) === "object")
			for(i in b)
				if(typeof(a[i]) === "object" && typeof(b[i]) === "object")
					a[i]= Object.assign(traverse(a[i], b[i]), a[i]);
				else
			 		Object.assign(combine(a, b), a);
		return a;
	}
	return obj1;
}

console.log(merge(obj1, obj2));

Upvotes: 1

Nick Parsons
Nick Parsons

Reputation: 50759

Since you mentioned you can use lodash you can use merge like so:

_.merge(obj1, obj2)

to get your desired result.

See working example below:

const a = {
  1: { foo: 1 },
  2: { bar: 2, fooBar: 3 },
  3: { fooBar: 3 },
},

b = {
  1: { foo: 1, bar: 2 },
  2: { bar: 2 },
  4: {foo: 1}
},

res = _.merge(a, b);
console.log(res);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>

Upvotes: 1

Code Maniac
Code Maniac

Reputation: 37755

You can use spread operator.

Update :

if obj2 has some properties that obj1 does not have?

Initially i wrote this answer assuming the keys are indexed like 0,1 and so on but as you mentioned in comment this is not the case than you can build a array of keys and than iterate over it as

as very concisely added in comment by @Nick [...Object.keys(obj1), ...Object.keys(obj2)]

let obj1 = {1: { foo: 1 },2: { bar: 2, fooBar: 3 },3: { fooBar: 3 },};
let obj2 = {1: { foo: 1, bar: 2 },2: { bar: 2 },};

let keys = [...new Set([...Object.keys(obj1),...Object.keys(obj2)])]
let  op = {}
let merged = keys.forEach(key=>{
  op[key] = {
    ...obj1[key],
    ...obj2[key]
  }
})
console.log(op)

Upvotes: 6

Related Questions