Reputation: 37
const map1 = Immutable.Map({ a: { x: 1, z: 1, y: 1, values: [1, 2, 3] } });
const map2 = Immutable.Map({ a: { x: 2, values: [4, 5, 6] } });
const map3 = map1.mergeDeep(map2)
// Output I want is:
// { a: { x: 2, z: 1, y: 1 values: [4, 5, 6] } }
Let's say I have two maps. One of the maps is a partial object of the other, doesn't necessarily contain all the same properties. I want to merge them, including the nested objects, but not merge the arrays. So as you can see above, it's updated the properties that exist in both maps, kept the old properties that don't exist in the new second map, and only used the latest map array rather than merging them into [1,2,3,4,5,6]. How can I do this?
Upvotes: 3
Views: 528
Reputation: 5039
You did not state the immutable.js version you used, but the way you asked, it is probably 4.0.0-rc12. The mergeDeep function of Immutable.js version 3.8.x did what you want; It replaced arrays instead of merging them. That's why @etarhan's answer works but does not for you.
There is no "nice" solution. The mergeDeepWith
function let's you define a merger function, but sadly the merger is only triggered on conflicts - so it does not help you either. All you can do is walk the object manually or upgrade immutable.js.
Also note that Immutable.Map({ a: { x: 1, z: 1, y: 1, values: [1, 2, 3] } });
does only convert the input shallowly. The array of values
stays an array. That is often undesired, you would want to have an Immutable.List instead of an array. To do so, use fromJS
, which converts depply.
I'll bring this up on the slack channel, IMO there should be the possbility to call the merger on collections too.
Something similar to this might do the job:
const map1 = Immutable.fromJS({ a: { x: 'one', z: 'old', y: 'old', values: [1, 2, 3] } });
const map2 = Immutable.fromJS({ a: { x: 'two', v: 'new', values: [4, 5, 6] } });
function mergeStuff(a, b, path = '') {
return a.withMutations(map => {
for(key of b.keys()) {
map.update(key, (val) => {
console.log('updating', path + key, val, b.get(key));
if(Immutable.isKeyed(val)) {
return mergeStuff(val, b.get(key), key + '.');
}
return b.get(key, val);
});
}
});
}
const map3 = mergeStuff(map1, map2);
console.log('result:');
console.log(map3);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.12/immutable.js"></script>
Upvotes: 0
Reputation: 4176
This question seems related to this stackoverflow post. As stated there using fromJS
instead of Map
gives the desired result. In addition this answer does a good job explaining the difference between the two. Please refer to and run the snippet below for a working example:
const map1 = Immutable.fromJS({ a: { x: 1, z: 1, y: 1, values: [1, 2, 3] } });
const map2 = Immutable.fromJS({ a: { x: 2, values: [4, 5, 6] } });
const map3 = map1.mergeDeep(map2)
console.log(map3)
// Output I want is:
// { a: { x: 2, z: 1, y: 1 values: [4, 5, 6] } }
/* And this snippet results in:
{
"a": {
"x": 2,
"z": 1,
"y": 1,
"values": [
4,
5,
6
]
}
}
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.js" integrity="sha512-9XVMKQr4ymAxO4jZVbEM2eq01aGlTY4bMlWyQh+KcQWprFkWu5KpOcDOa3RLFZc586QHihZPd1b8XzXqweRxIQ==" crossorigin="anonymous"></script>
Upvotes: 1