I am trying to overwrite an object given specific changes to that object. The problem is that the code I have currently is just overwriting the first object in newBody. So the AndroidText object gets replaced with the iphoneText one. I want the AndroidText object to be there and have it replace the iphoneText one.
const deviceChanges = {
"a": 5,
"card": {
"back": [
{
"key": "iphoneText",
"label": "IPHONE",
"value": "UPDATED VALUE FOR IPHONE"
},
]
}
};
let newBody = {
"a": 3,
"card": {
"back": [
{
"key": "androidText",
"label": "ANDROID",
"value": "androidOS"
},
{
"key": "samsungText",
"label": "SAMSUNG",
"value": "samsungOS"
},
{
"key": "iphoneText",
"label": "IPHONE",
"value": "iphone"
},
{
"key": "macbookText",
"label": "MACBOOK",
"value": "macbookOS"
}
]
},
"c": 8
};
const expected = {
"object": {
"a": 5,
"card": {
"back": [
{
"key": "androidText",
"label": "ANDROID",
"value": "androidOS"
},
{
"key": "samsungText",
"label": "SAMSUNG",
"value": "samsungOS"
},
{
"key": "iphoneText",
"label": "IPHONE",
"value": "UPDATED VALUE FOR IPHONE"
},
{
"key": "macbookText",
"label": "MACBOOK",
"value": "macbookOS"
}
]
},
"c": 8
}
};
I have tried this code:
function merge(target, source) {
for (const [key, value] of Object.entries(source)) {
if (key in target) {
if (typeof value === 'object' && typeof target[key] === 'object') {
merge(target[key], value);
} else {
target[key] = value;
}
} else {
// the key in source isn't in the target. add it
target[key] = value;
}
}
return target;
}
But with this code does not seem to work for this example. It is replacing the "androidText" object with the "iphone" one.. I think its because the first object in the array? How would you fix this?
CodePudding user response:
Here's the original function updated to detect an array being merged. When an array is found, the function is no longer generic; instead, it matches the target array based on matching values for the key
prop, and then updates (or adds) the source object:
const deviceChanges = {
"a": 5,
"card": {
"back": [{
"key": "iphoneText",
"label": "IPHONE",
"value": "UPDATED VALUE FOR IPHONE"
}, ]
}
};
let newBody = {
"a": 3,
"card": {
"back": [{
"key": "androidText",
"label": "ANDROID",
"value": "androidOS"
},
{
"key": "samsungText",
"label": "SAMSUNG",
"value": "samsungOS"
},
{
"key": "iphoneText",
"label": "IPHONE",
"value": "iphone"
},
{
"key": "macbookText",
"label": "MACBOOK",
"value": "macbookOS"
}
]
},
"c": 8
};
console.log(merge(newBody, deviceChanges))
function merge(target, source) {
return (Array.isArray(target)) ? mergeArray(target, source) : mergeObject(target, source);
}
// just like the original function
function mergeObject(target, source) {
for (const [key, value] of Object.entries(source)) {
if (key in target) {
if (typeof value === 'object' && typeof target[key] === 'object') {
merge(target[key], value);
} else {
target[key] = value;
}
} else {
// the key in source isn't in the target. add it
target[key] = value;
}
}
return target;
}
// not generic like the object merge, this looks up source objects
// in target by matching key, merges if found, pushes otherwise
function mergeArray(target, source) {
source.forEach(s => {
let t = target.find(obj => obj.key === s.key);
t ? merge(t, s) : target.push(s);
})
}