I built a method using reduce
of JS to aggregate together data from a DB in a better shape.
What I'm wondering is, if that method can be simplified with a more modern approach or better written. Like using a different method instead of a reduce.
The snippet of the method will be included at the end of the post.
The method takes the dbData
which includes data in the following form
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_CALLCENTER',
current: 3,
total: 9,
},
]
The data contains two same fields/values as studyId
and siteId
and what I aggregate is the status
, cuurent
, total
tobe included under the same Study and Site.
The output of the above passing via the method
[
{
"studyId": "X",
"siteId": "A",
"currents": {
"PENDING_CALLCENTER": 5,
"PENDING_SITE": 3
},
"totals": {
"PENDING_CALLCENTER": 17,
"PENDING_SITE": 9
}
},
{
"studyId": "Y",
"siteId": "B",
"currents": {
"PENDING_SITE": 6,
"PENDING_CALLCENTER": 3
},
"totals": {
"PENDING_SITE": 18,
"PENDING_CALLCENTER": 9
}
}
]
So it is reduced to a different form where we have one object per studyId
and siteId
which includes the currents
and totals
of the status
The method
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;
}, []);
A working example
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_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);