I have a javascript array object from a database input like this:
[{ date: '2021-09-15', type: 'cats', value: 4 },
{ date: '2021-09-15', type: 'dogs', value: 5 },
{ date: '2021-09-16', type: 'cats', value: 1 },
{ date: '2021-09-16', type: 'dogs', value: 4 }]
And I need an output like this:
[{ date: '2021-09-15', cats: 4, dogs: 5 },
{ date: '2021-09-16', cats: 1, dogs: 4 }]
I am trying to use the reduce function by this way, however, I can't get it to work (it's grouping the data but not modifying it thus, they are left with a single value)
const data = [
{ date: '2021-09-15', type: 'cats', value: 4 },
{ date: '2021-09-15', type: 'dogs', value: 5 },
{ date: '2021-09-16', type: 'cats', value: 1 },
{ date: '2021-09-16', type: 'dogs', value: 4 }
]
const groups = data.reduce((groups, item) => {
const key = item[item.date];
if (!groups[key]) {
groups[item.date] = []
}
if (item.type == "cats") {
item.cats = item.value;
} else if (item.type == "dogs") {
item.dogs = item.value;
}
groups[item.date].push(item);
return groups;
}, {});
console.log(groups)
.as-console-wrapper { max-height: 100% !important; }
CodePudding user response:
If second object with same date
and already existing type
. This also covers the case where you have multiple objects with same type
then it will add up the value
const arr = [
{ date: "2021-09-15", type: "cats", value: 4 },
{ date: "2021-09-15", type: "cats", value: 5 },
{ date: "2021-09-16", type: "cats", value: 1 },
{ date: "2021-09-16", type: "dogs", value: 4 },
];
const map = new Map();
arr.forEach((o) => {
const { date, type, value } = o;
if (!map.has(date)) map.set(o.date, { date, [type]: value });
else {
const target = map.get(date);
const { type: newType, value: newValue } = o;
target[newType] = target[newType] ? target[newType] newValue : newValue;
}
});
const result = [...map.values()];
console.log(result);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
CodePudding user response:
This is really a two-step process...
- Collect the data grouped by
date
into a map - Transform the final result into the array you want
const data = [{"date":"2021-09-15","type":"cats","value":4},{"date":"2021-09-15","type":"dogs","value":5},{"date":"2021-09-16","type":"cats","value":1},{"date":"2021-09-16","type":"dogs","value":4}]
const t1 = performance.now()
const mapped = data.reduce((map, { date, type, value }) => {
// get the current entry for date, default to `{}`
const obj = map.get(date) ?? {}
// merge and set the new entry
return map.set(date, {
...obj,
[ type ]: (obj[type] ?? 0) value
})
}, new Map())
const groups = Array.from(mapped, ([ date, obj ]) => ({
date,
...obj
}))
const t2 = performance.now()
console.log(groups, `\nTook ${t2 - t1}ms`)
.as-console-wrapper { max-height: 100% !important; }
It wasn't clear from your question but this answer sums up any same type values for the same date.