update I tried my own solution and this is what I did maybe can be done better
const dbData = [{
studyId: 'X',
siteId: 'A',
day: '2000-01-01',
status: 'PENDING_CALLCENTER',
current: 5,
total: 17,
},
{
studyId: 'X',
siteId: 'A',
day: '2000-01-01',
status: 'PENDING_SITE',
current: 3,
total: 9,
},
{
studyId: 'Y',
siteId: 'B',
day: '2000-01-01',
status: 'PENDING_SITE',
current: 3,
total: 9,
},
{
studyId: 'Y',
siteId: 'B',
day: '2000-01-01',
status: 'PENDING_SITE',
current: 3,
total: 9,
},
{
studyId: 'Y',
siteId: 'B',
day: '2000-01-01',
status: 'PENDING_CALLCENTER',
current: 3,
total: 9,
},
];
const reduced = dbData.reduce((acc, row) => {
const {
studyId,
siteId,
status,
current,
total
} = row;
const idx = acc.findIndex(x => studyId === x.studyId && siteId === x.siteId);
const item = idx === -1 ? {
studyId,
siteId,
currents: {},
totals: {}
} : { ...acc[idx]
};
item.currents[status] = item.currents[status] ? item.currents[status] + current : current;
item.totals[status] = item.totals[status] ? item.totals[status] + total : total;
if (idx === -1) {
acc.push(item);
} else {
acc[idx] = item;
}
return acc;
}, []);
console.log(reduced);
I'm new to using reduce and I have some difficulties understanding how to use it correctly.
I would like to solve a problem where I need to reduce some data in a new array of obj with a different shape.
I have some data
[
{
studyId: 'X',
siteId: 'A',
day: '2000-01-01',
status: 'PENDING_CALLCENTER',
current: 5,
total: 17,
},
{
studyId: 'X',
siteId: 'A',
day: '2000-01-01',
status: 'PENDING_SITE',
current: 3,
total: 9,
},
];
I want to reduce this to this new data
[
{
studyId: 'X',
siteId: 'A',
currents: {
PENDING_CALLCENTER: 5,
PENDING_SITE: 3,
},
totals: {
PENDING_CALLCENTER: 17,
PENDING_SITE: 9,
},
},
];
To learn I was able to create a reducer which calc sum and that I did it but the above problem I have just difficulties to start and want to understand it.
You can try something like this :
Please note - I haven't considered validation/exception handling. This is just one way of using a reduce for your data. You could also find a cute way of reducing lines of code - feel free :-)
const arr = [
{
studyId: 'X',
siteId: 'A',
day: '2000-01-01',
status: 'PENDING_CALLCENTER',
current: 5,
total: 17,
},
{
studyId: 'X',
siteId: 'A',
day: '2000-01-01',
status: 'PENDING_SITE',
current: 3,
total: 9,
},
];
const res = arr.reduce((accum, curr) => {
const exist = accum.find(e => e.studyId === curr.studyId && e.siteId === curr.siteId);
if (exist) {
exist.currents[curr.status] += curr.current;
exist.totals[curr.status] += curr.total;
} else {
const elem = {
studyId: curr.studyId,
siteId: curr.siteId,
currents: {
PENDING_CALLCENTER: 0,
PENDING_SITE: 0,
},
totals: {
PENDING_CALLCENTER: 0,
PENDING_SITE: 0,
}
}
elem.currents[curr.status] = curr.current;
elem.totals[curr.status] = curr.total;
accum.push(elem);
}
return accum;
}, []);
console.log(res);
Output:
[
{
studyId: 'X',
siteId: 'A',
currents: { PENDING_CALLCENTER: 5, PENDING_SITE: 3 },
totals: { PENDING_CALLCENTER: 17, PENDING_SITE: 9 }
}
]
The following reducer functionality just merges the currents and totals values of objects of same IDs. Thus, for duplicate items like provided by the OP with a duplicate for Y/B, number values for same properties will be overwritten but not summed-up.
function mergeCurrentsAndTotalsOfSameIds({ lookup = new Map, result }, item) {
const { studyId, siteId, status, current, total } = item;
const mergerKey = [studyId, '_###_', siteId].join('');
let merger = lookup.get(mergerKey);
if (!merger) {
merger = { studyId, siteId, currents: {}, totals: {} };
lookup.set(mergerKey, merger);
result.push(merger);
}
merger.currents[status] = current;
merger.totals[status] = total;
return { lookup, result };
}
const dbData = [{
studyId: 'X',
siteId: 'A',
day: '2000-01-01',
status: 'PENDING_CALLCENTER',
current: 5,
total: 17,
}, {
studyId: 'X',
siteId: 'A',
day: '2000-01-01',
status: 'PENDING_SITE',
current: 3,
total: 9,
}, {
studyId: 'Y',
siteId: 'B',
day: '2000-01-01',
status: 'PENDING_SITE',
current: 3,
total: 9,
}, {
studyId: 'Y',
siteId: 'B',
day: '2000-01-01',
status: 'PENDING_SITE',
current: 3,
total: 9,
}, {
studyId: 'Y',
siteId: 'B',
day: '2000-01-01',
status: 'PENDING_CALLCENTER',
current: 3,
total: 9,
}];
const { result: mergedData } = dbData
.reduce(mergeCurrentsAndTotalsOfSameIds, {result: [] })
console.log({ mergedData, dbData });
.as-console-wrapper { min-height: 100%!important; top: 0; }