Reputation: 435
In my code I have two arrays, first one contains multiple objects. While the second one is to store serialized form data (mapped to JSON). So both arrays are having identical keys.
What I want to achieve is to update the values of an object in the original array based on the values of an object in new array dynamically, by ID in the object.
Found some examples online but hard to get them to work. Because most of them are showing either one level of objects but I'm working on complex nested objects in the array.
var products = [
{
Id: 1,
Name: 'Product1',
Attributes: {
Storage: 'Normal',
Size: 'Small'
}
},
{
Id: 2,
Name: 'Product2',
Attributes: {
Storage: 'Normal',
Size: 'Small'
}
}
];
var newData = [
{
Id: 2,
Name: 'French Fries'
},
{
Id: 1,
Attributes: {
Size: 'Medium'
}
}
];
The expected outcome is the products
array now updated with the values from the second array.
Output:
[
{
Id: 1,
Name: 'Product1',
Attributes: {
Storage: 'Normal',
Size: 'Medium'
}
},
{
Id: 2,
Name: 'French Fries',
Attributes: {
Storage: 'Normal',
Size: 'Small'
}
}
]
Upvotes: 2
Views: 1379
Reputation: 386560
You could take a Map
for the update items and iterate products
.
If an item is found for an update, take a recursive approach and iterate the entries and check if the value is an object, then iterate the nested properties.
If no nested object found update the property.
This works for arrays as well.
function update(target, source) {
Object.entries(source).forEach(([key, value]) => {
if (value && typeof value === 'object') {
update(target[key] = target[key] || (Array.isArray(value) ? [] : {}), value);
} else if (target[key] !== value) {
target[key] = value;
}
});
}
var products = [{ Id: 1, Name: 'Product1', Attributes: { Storage: 'Normal', Size: 'Small' } }, { Id: 2, Name: 'Product2', Attributes: { Storage: 'Normal', Size: 'Small' } }],
newData = [{ Id: 2, Name: 'French Fries' }, { Id: 1, Attributes: { Size: 'Medium' } }],
map = new Map(newData.map(o => [o.Id, o]));
products.forEach(o => map.has(o.Id) && update(o, map.get(o.Id)));
console.log(products);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 3
Reputation: 36564
You can create a function which combine nested objects. And then use map()
and find()
to create combined array of objects.
var products = [
{
Id: 1,
Name: 'Product1',
Attributes: {
Storage: 'Normal',
Size: 'Small'
}
},
{
Id: 2,
Name: 'Product2',
Attributes: {
Storage: 'Normal',
Size: 'Small'
}
}
];
var newData = [
{
Id: 2,
Name: 'French Fries'
},
{
Id: 1,
Attributes: {
Size: 'Medium'
}
}
];
const haveNested = obj => Object.values(obj).some(x => typeof x === "object");
function combine(obj1,obj2){
if(!haveNested(obj1)) return ({...obj1,...obj2})
let res = obj1
for(let key in obj1){
if(typeof obj1[key] === "object"){
res[key] = combine(obj1[key],obj2[key]);
}
else if(obj2[key]) res[key] = obj2[key]
}
return res;
}
const result = products.map(x => {
let temp = newData.find(a => a.Id === x.Id);
return temp ? combine(x,temp) : x;
})
console.log(result)
Upvotes: 0