I have an object that can be deeply nested with objects, arrays, arrays of objects, and so on.
Every nested object has a sys
property which in turn has an id
property.
I have a separate list of id
values that correspond to objects that I want to remove from the original object. How can I go about recursively looping through the entire object and modify it to no longer include these?
For example, say I have the following data:
let data = {
sys: {
id: '1'
},
items: [
{
sys: {
id: '2'
},
fields: {
title: 'Item title',
sponsor: {
sys: {
id: '3'
},
fields: {
title: 'Sponsor Title'
}
},
actions: [
{
sys: {
id: '4'
},
fields: {
title: 'Google',
url: 'google.com'
}
},
{
sys: {
id: '5'
},
fields: {
title: 'Yahoo',
url: 'yahoo.com'
}
}
]
}
}
]
}
Then I have an array of id
's to remove:
const invalidIds = ['3', '5'];
After I run the function, the resulting object should have the property with sys.id
of '3'
set to null
, and the object with sys.id
of '5'
should simply be removed from its containing array:
// Desired Output:
{
sys: {
id: '1'
},
items: [
{
sys: {
id: '2'
},
fields: {
title: 'Item title',
sponsor: null,
actions: [
{
sys: {
id: '4'
},
fields: {
title: 'Google',
url: 'google.com'
}
}
]
}
}
]
}
With help from this solution, I'm able to recursively search through the object and its various nested arrays:
const process = (key, value) => {
if (typeof value === 'object' && value.sys && value.sys.id && invalidIds.includes(value.sys.id)) {
console.log('found one', value.sys.id);
}
};
const traverse = (obj, func) => {
for (let key in obj) {
func.apply(this, [key, obj[key]]);
if (obj[key] !== null) {
if (typeof obj[key] === 'object') {
traverse(obj[key], func);
} else if (obj[key].constructor === Array) {
obj[key].map(item => {
if (typeof item === 'object') {
traverse(item, func);
}
});
}
}
}
};
traverse(data, process);
However I can't figure out how to properly modify the array. In addition, I'd prefer to create an entirely new object rather than modify the existing one in order to keep things immutable.