2
\$\begingroup\$

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 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, current, total to be 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);

asked May 21, 2022 at 11:46
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

A couple of things that can be simplified/refactored:

  • Conditionals can be reduced to improve code readability.
  • No need to clone an object if it already exists. Instead, we can just update the currents and totals properties.

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);
 
 if (idx === -1) {
 const item = {
 studyId,
 siteId,
 currents: {
 [status]: current, 
 },
 totals: {
 [status]: total,
 },
 };
 
 acc.push(item);
 } else {
 acc[idx].currents[status] = (acc[idx].currents[status] || 0) + current;
 acc[idx].totals[status] = (acc[idx].totals[status] || 0) + total;
 }
 
 return acc;
}, []);
console.log(reduced);

answered May 22, 2022 at 8:32
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.