3

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.

6
  • 1
    Possible duplicate of How can I merge properties of two JavaScript objects dynamically? Commented Jan 26, 2019 at 7:58
  • 1
    No, because that question does not consider merging the properties too. Commented Jan 26, 2019 at 8:00
  • What's supposed to happen if obj1.2.bar is 2 but obj2.2.bar is 3? Anyway, it should be closed as "too broad" then, because SO isn't a free code writing service. Commented Jan 26, 2019 at 8:02
  • Possible duplicate of stackoverflow.com/questions/50176456/… Commented Jan 26, 2019 at 8:23
  • I'm sorry for that :( Commented Jan 28, 2019 at 2:39

6 Answers 6

6

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)

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

4 Comments

Thanks, but what if obj2 has some properties that obj1 does not have? :(
@Taichi Not the original writer of the answer but I think by changing Objects.keys(obj1).forEach to [...Object.keys(obj1), ...Object.keys(obj2)].forEach should do the trick
@NickParsons this is so neat, i was writing a function to achieve this. cheers mate :)
@CodeManiac no worries, just another thought, maybe by settings keys equal to [...new Set([...Object.keys(obj1),...Object.keys(obj2)])]; would be better to remove duplicates... Also, I think merged should be merged = keys.forEach() ;)
1

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>

Comments

1

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));

Comments

0

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

Comments

0

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",
}

*/

Comments

0

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.

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.