Reputation: 4048
I have two arrays of objects that contain addresses that have a label and an object for the actual address:
var originalAddresses = [
{
label: 'home',
address: { city: 'London', zipCode: '12345' }
},
{
label: 'work',
address: { city: 'New York', zipCode: '54321' }
}
];
var updatedAddresses = [
{
label: 'home',
address: { city: 'London (Central)', country: 'UK' }
},
{
label: 'spain',
address: { city: 'Madrid', zipCode: '55555' }
}
];
Now I want to merge these arrays by label
and compare the individual properties of the addresses and merge only the properties from the new address that are actually present. So the result should look like this:
var result = [
{
label: 'home',
address: { city: 'London (Central)', zipCode: '12345', country: 'UK' }
},
{
label: 'work',
address: { city: 'New York', zipCode: '54321' }
},
{
label: 'spain',
address: { city: 'Madrid', zipCode: '55555' }
}
]
How can I do this using lodash? I tried a combination of unionBy()
and merge()
. With unionBy() I was able to compare and join the arrays by label, but this always replaces the whole object. I can sure merge the addresses but this doesn't happen by label then.
Upvotes: 51
Views: 114792
Reputation: 2800
Use defaultsDeep
:
console.log(_.defaultsDeep(
{
'x': { 'y': 20 }
},
{
'x': { 'y': 10, 'z': 30 }
}
));
Output:
{ 'x': { 'y': 20, 'z': 30 } }
Upvotes: 1
Reputation: 19
I try to use VanillaJS to handle this.
const originalAddresses = [{
label: 'home',
address: {
city: 'London',
zipCode: '12345'
}
}, {
label: 'work',
address: {
city: 'New York',
zipCode: '54321'
}
}];
const updatedAddresses = [{
label: 'home',
address: {
city: 'London (Central)',
country: 'UK'
}
}, {
label: 'spain',
address: {
city: 'Madrid',
zipCode: '55555'
}
}];
const groupBy = (array, property) => {
return array.reduce((acc, cur) => {
let key = cur[property]
if (!acc[key]) {
acc[key] = []
}
acc[key].push(cur)
return acc
}
, {})
}
const groupByLabel = groupBy([...originalAddresses, ...updatedAddresses], 'label')
const result = Object.keys(groupByLabel).map((key) => {
return {
label: groupByLabel[key][0].label,
address: groupByLabel[key].reduce((acc, cur) => {
return Object.assign(acc, cur.address)
}
, {})
}
}
)
console.log(result)
Upvotes: 1
Reputation: 191976
You can turn both arrays into objects using _.keyBy(arr, 'label')
, and then merge deep using _.merge()
:
var originalAddresses = [{
label: 'home',
address: {
city: 'London',
zipCode: '12345'
}
}, {
label: 'work',
address: {
city: 'New York',
zipCode: '54321'
}
}];
var updatedAddresses = [{
label: 'home',
address: {
city: 'London (Central)',
country: 'UK'
}
}, {
label: 'spain',
address: {
city: 'Madrid',
zipCode: '55555'
}
}];
var result = _.values(_.merge(
_.keyBy(originalAddresses, 'label'),
_.keyBy(updatedAddresses, 'label')
));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Upvotes: 59