Reputation: 361
This is what I have:
const arrayA = [{name:'a', amount: 10, serviceId: '23a', test:'SUCCESS'},
{name:'a', amount: 9, test:'FAIL'},
{name:'b', amount: 15, serviceId: '23b', test:'SUCCESS'}]
(note that there's object not having 'serviceId')
I would like to get:
[{name:'a', amount: 19, test:'FAIL'},
{name:'b', amount: 15, test:'SUCCESS'}]
amount
field grouped by name.FAIL
if there's any object with the value FAIL
(grouped by name)serviceId
and don't want to include it in the new object.I have searched, and tried something like this: (reference: https://stackoverflow.com/a/50338360/13840216)
const result = Object.values(arrayA.reduce((r, o) => (r[o.name]
? (r[o.name].amount += o.amount)
: (r[o.name] = {...o}), r), {}));
but still not sure how to assign test
field.
Any help would be appreciated!
Upvotes: 0
Views: 1928
Reputation: 136
That is a nice use case of how to process data in js, particularly how functions like map
and reduce
can help you do that processing. Which are a nice alternative to loops and iterations.
Moreover, I'd advise you to do the processing in steps, as you have defined in the description. For example:
const arrayA = [
{name:'a', amount: 10, serviceId: '23a', test:'SUCCESS'},
{name:'a', amount: 9, test:'FAIL'},
{name:'b', amount: 15, serviceId: '23b', test:'SUCCESS'}
]
// First group the items by name
const byName = arrayA.reduce((ob, item) => {
if(!(item.name in ob))
ob[item.name] = []
ob[item.name].push({amount: item.amount, test: item.test})
return ob
}, {})
// Then compute the total amount in each group and find if there is any FAIL in a group
const sumByName = Object.keys(byName).map(name => { // This is a way to iterate through the groups
// Sum the amount in all elements of a group
const amount = byName[name].reduce((sum, item) => sum + item.amount , 0)
// Find if there is any FAIL in a group
const test = byName[name].map(item => item.test) // Get an array with only the test string
.includes('FAIL') ? 'FAIL': 'SUCCESS' // Evaluate if the array includes FAIL
return ({name, amount, test})
})
console.log(sumByName)
Finally, I'd advise you to watch these videos on map and reduce (and all the content of that channel for this matter)
Upvotes: 1
Reputation: 2783
Store the sums and final values in an object and then convert them into an array.
const arrayA = [
{ name: "a", amount: 10, serviceId: "23a", test: "SUCCESS" },
{ name: "a", amount: 9, test: "FAIL" },
{ name: "b", amount: 15, serviceId: "23b", test: "SUCCESS" },
];
const map = {};
arrayA.forEach((row) => {
if (!map[row.name]) {
map[row.name] = { name: row.name, amount: 0, test: "SUCCESS" };
}
map[row.name].amount += row.amount;
if (row.test === "FAIL") {
map[row.name].test = "FAIL";
}
});
const result = Object.values(map);
console.log(result);
Upvotes: 1
Reputation: 4217
you can use Array.reduce
method:
const arrayA=[{name:"a",amount:10,serviceId:"23a",test:"SUCCESS"},{name:"a",amount:9,test:"FAIL"},{name:"b",amount:15,serviceId:"23b",test:"SUCCESS"}];
let result = arrayA.reduce((aac,{name,amount,test}) => {
let idx = aac.findIndex(n => n.name === name)
if( idx != -1){
aac[idx].amount += amount;
if(test === "FAIL")
aac[idx].test = "FAIL"
return aac
}
aac.push({name,amount,test})
return aac
},[])
console.log(result);
console.log(arrayA)
Upvotes: 0
Reputation: 177786
This? Just test if the .test is already fail
const arrayA = [{ name: 'a', amount: 10, serviceId: '23a', test: 'SUCCESS' }, { name: 'a', amount: 9, test: 'FAIL' }, { name: 'b', amount: 15, serviceId: '23b', test: 'SUCCESS' }],
result = Object.values(
arrayA.reduce((r, o) => {
r[o.name] ? (r[o.name].amount += o.amount) : (r[o.name] = { ...o })
r[o.name].test = r[o.name].test === "FAIL" ? "FAIL" : o.test;
return r;
}, {})
);
console.log(result);
Upvotes: 2
Reputation: 386560
You need to check test
and update the value, if necessary.
const
array = [{ name: 'a', amount: 10, serviceId: '23a', test: 'SUCCESS' }, { name: 'a', amount: 9, test: 'FAIL' }, { name: 'b', amount: 15, serviceId: '23b', test: 'SUCCESS' }],
result = Object.values(array.reduce((r, { name, amount, test }) => {
if (!r[name]) r[name] = { name, amount: 0, test };
r[name].amount += amount;
if (test === 'FAIL') r[name].test = 'FAIL';
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 5