Is there a way to compare an incomplete array to the source of truth array & return the missing elements? The array consists of objects & some of the objects have an array of objects.
let incompleteArr =[
{
"name": "Extra Toppings (Small)",
"modifier_options": [{
"name": "Corn",
"price": 0.75
},
{
"name": "Extra mozzarella",
"price": 0.9
},
{
"name": "Onion",
"price": 0.45
}
]
},
{
"name": "Extra Toppings (Large)",
"modifier_options": [{
"name": "Corn",
"price": 1.2
},
{
"name": "Extra Mozzarella",
"price": 1.7
}
]
}
]
}]
let completeArr =[
{
"name": "Extra Toppings (Small)",
"modifier_options": [
{
"name": "Corn",
"price": 0.75
},
{
"name": "Extra mozzarella",
"price": 1.2
},
{
"name": "Extra Anchovies",
"price": 0.7
}
]
},
{
"name": "Extra Toppings (Large)",
"modifier_options": [
{
"name": "Corn",
"price": 1.2
},
{
"name": "Extra mozzarella",
"price": 1.7
}
]
},
{
"name": "Extra Burger Toppings (Small)",
"modifier_options": [
{
"name": "Extra Onion",
"price": 0.5
},
{
"name": "Extra Tomato",
"price": 0.55
},
{
"name": "Extra Cheese",
"price": 0.65
},
{
"name": "Extra Mayo",
"price": 0.3
},
{
"name": "Extra Patty",
"price": 2.5
}
]
},
{
"name": "Extra Burger Toppings (Medium)",
"modifier_options": [
{
"name": "Extra Onion",
"price": 0.6
},
{
"name": "Extra Tomato",
"price": 0.65
},
{
"name": "Extra Cheese",
"price": 0.75
},
{
"name": "Extra Mayo",
"price": 0.4
},
{
"name": "Extra Patty",
"price": 2.9
}
]
},
{
"name": "Extra Burger Toppings (Large)",
"modifier_options": [
{
"name": "Extra Onion",
"price": 0.8
},
{
"name": "Extra Tomato",
"price": 0.9
},
{
"name": "Extra Cheese",
"price": 0.95
},
{
"name": "Extra Mayo",
"price": 0.6
},
{
"name": "Extra Patty",
"price": 3.5
}
]
}
]
Desired result is to return an array of missing elements. For example the "name" Extra Toppings (Small) must exist in the incompleteArr & the completeArr. Then the "modifier_options" must also be compared. Any modifier_options not in the incompleteArr must be pushed into the array of missing elements.
I have tried this so far
let missingMod = gfMods.filter(mod => lvMods.every(mod2 => !mod2.name.includes(mod.name)))
The output as expected is the missing items BUT I am not getting the missing nested array items from the modifier_options object. I have an idea that I need to loop through the arrays checking that the "names" exist & then a second loop to check if the modifier_options all exist. This is where I have been stuck.
[{
name:"Extra Burger Toppings (Small)",
modifier_options: [{
name:"Extra Onion",
price:0.5},
{name:"Extra Tomato",
price:0.55},
{name:"Extra Cheese",
price:0.65},
{name:"Extra Mayo",
price:0.3},
{name:"Extra Patty",
price:2.5}
]},
{name:"Extra Burger Toppings (Medium)",
modifier_options: [{
name:"Extra Onion",
price:0.6},
{name:"Extra Tomato",
price:0.65},
{name:"Extra Cheese",
price:0.75},
{name:"Extra Mayo",
price:0.4},
{name:"Extra Patty",
price:2.9}]
},
{name:"Extra Burger Toppings (Large)",
modifier_options: [{
name:"Extra Onion",
price:0.8},
{name:"Extra Tomato",
price:0.9},
{name:"Extra Cheese",
price:0.95},
{name:"Extra Mayo",
price:0.6},
{name:"Extra Patty",
price:3.5}]
}]
This solution utilizes the .reduce()
, .find()
, .some()
, and .filter()
Array methods.
// Reduces the complete array, to a list of missing values from
// the incomplete array.
const result = completeArr.reduce((prev, next) => {
// Finds whether the object exists in the incomplete array.
// _main will hold the matching object from the incomplete
// array if found, or undefined otherwise.
const _main = incompleteArr.find(obj => obj.name == next.name);
// If it does find, stop here and check for missing
// values inside modifier options.
if(_main){
// .filter to get the missing modifier objects from the
// incomplete array. Done by checking if a
// modifier option of the complete array
// is NOT present in the incomplete array's
// modifier options list.
const _mod = next.modifier_options.filter(next_mod => !_main.modifier_options.some(main_mod => next_mod.name == main_mod.name));
// Add _mod(containing missing modifier options) to
// the accumulating array and return.
return [...prev, {parent: next.name, modifier_options: _mod}];
}
// This next object doesn't exist in the incomplete
// array as it wasn't found, so add it to the accumulating
// list of missing items.
return [...prev, next];
}, []);
let incompleteArr = [
{
"name": "Extra Toppings (Small)",
"modifier_options": [{
"name": "Corn",
"price": 0.75
},
{
"name": "Extra mozzarella",
"price": 0.9
},
{
"name": "Onion",
"price": 0.45
}
]
},
{
"name": "Extra Toppings (Large)",
"modifier_options": [{
"name": "Corn",
"price": 1.2
},
{
"name": "Extra Mozzarella",
"price": 1.7
}
]
}
];
let completeArr = [
{
"name": "Extra Toppings (Small)",
"modifier_options": [
{
"name": "Corn",
"price": 0.75
},
{
"name": "Extra mozzarella",
"price": 1.2
},
{
"name": "Extra Anchovies",
"price": 0.7
}
]
},
{
"name": "Extra Toppings (Large)",
"modifier_options": [
{
"name": "Corn",
"price": 1.2
},
{
"name": "Extra mozzarella",
"price": 1.7
}
]
},
{
"name": "Extra Burger Toppings (Small)",
"modifier_options": [
{
"name": "Extra Onion",
"price": 0.5
},
{
"name": "Extra Tomato",
"price": 0.55
},
{
"name": "Extra Cheese",
"price": 0.65
},
{
"name": "Extra Mayo",
"price": 0.3
},
{
"name": "Extra Patty",
"price": 2.5
}
]
},
{
"name": "Extra Burger Toppings (Medium)",
"modifier_options": [
{
"name": "Extra Onion",
"price": 0.6
},
{
"name": "Extra Tomato",
"price": 0.65
},
{
"name": "Extra Cheese",
"price": 0.75
},
{
"name": "Extra Mayo",
"price": 0.4
},
{
"name": "Extra Patty",
"price": 2.9
}
]
},
{
"name": "Extra Burger Toppings (Large)",
"modifier_options": [
{
"name": "Extra Onion",
"price": 0.8
},
{
"name": "Extra Tomato",
"price": 0.9
},
{
"name": "Extra Cheese",
"price": 0.95
},
{
"name": "Extra Mayo",
"price": 0.6
},
{
"name": "Extra Patty",
"price": 3.5
}
]
}
];
const result = completeArr.reduce((prev, next) => {
const _main = incompleteArr.find(obj => obj.name == next.name);
if(_main){
const _mod = next.modifier_options.filter(next_mod => !_main.modifier_options.some(main_mod => next_mod.name == main_mod.name));
return [...prev, {parent: next.name, modifier_options: _mod}];
}
return [...prev, next];
}, []);
console.log(result);
Note: It'll return "Extra mozzarella" from "Extra Toppings (Large)" because of the case difference. Also, forgive the poor variable names, I hope this solution solves your problem.
As per the request of OP, I added the .name
of the parent object the missing modifier_options
belong to.