Reputation: 79
I have some dynamic data. Assume that id will always be present, and the other key:values will change.
I am trying to wrap my head around an abstract approach, but I don't think I know enough about the tools I have available.
I am looking for an approach to aggregate dynamically.
example, if I have this data:
const dataum = [{
"id": 1,
"q1": "yes",
"q2": 4,
"q3": null
}, {
"id": 2,
"q1": null,
"q2": 14,
"q3": "medium"
}, {
"id": 3,
"q1": "no",
"q2": 83,
"q3": "high"
}, {
"id": 27,
"q1": "yes",
"q2": 62,
"q3": null
}]
and am attempting to create something like this:
const aggData = [{
"q1": {
"yes": 2,
"empty": 1,
"no": 1
}
}, {
"q2": {
"0to60": 2,
"60to70": 1,
"70to100": 1,
"empty": 0
}
} {
"q3": {
"medium": 1,
"empty": 2,
"high": 1
}
}]
I haven't tried much. because I am stuck at the outer most process / function. I have thought about for() .keys and .values, I have looked at array.reduce()
... but I still do not get how to be able to dynamically say: newObject.key.someAnswer += 1
where the key is dynamic, and the answer is dynamic (or null).
I wouldn't worry too much about the ranges... I think with a tiny bit of help I can fork the process.
I can provide some more data to this process, in any format, like:
const qProperties = [{
"q1": {
"type": "YN",
"values": ["yes", "no"]
}
}, {
"q3": {
"type": "LMH",
"values": ["low", "medium", "high"]
}
}]
If it would help reduce the code footprint, make it more abstract.
Upvotes: 2
Views: 218
Reputation: 2000
You could use lodash.groupby
if you're not bothered about the implementation.
https://www.npmjs.com/package/lodash.groupby
const groupBy = require('lodash.groupby');
const keys = ["q1", "q2", "q2"];
const dataum = [
{ id: 1, q1: "yes", q2: 4, q3: null },
{ id: 2, q1: null, q2: 14, q3: "medium" },
{ id: 3, q1: "no", q2: 83, q3: "high" },
{ id: 27, q1: "yes", q2: 62, q3: null }
];
const grouped = [];
function countKeys(object) {
const counts = [];
const keys = Object.keys(object);
keys.forEach((key) => {
const count = Object.values(object[key]).length;
counts.push({ [key]: count });
});
return counts;
}
keys.forEach((key) => {
const groups = _.groupBy(dataum, key);
const counts = countKeys(groups);
const groupedRow = { [key]: counts };
grouped.push(groupedRow);
});
console.log(grouped);
// const output = [
// { q1: [{ yes: 2 }, { null: 1 }, { no: 1 }] },
// { q2: [{ "4": 1 }, { "14": 1 }, { "62": 1 }, { "83": 1 }] },
// { q2: [{ "4": 1 }, { "14": 1 }, { "62": 1 }, { "83": 1 }] }
// ];
Upvotes: 1
Reputation: 1833
Although your input data does not really match your expected output data (which is probably why you got the downvote), I think you want something like that:
const dataum = [
{ id: 1, q1: "yes", q2: 4, q3: null },
{ id: 2, q1: null, q2: 14, q3: "medium" },
{ id: 3, q1: "no", q2: 83, q3: "high" },
{ id: 27, q1: "yes", q2: 62, q3: null },
];
const intermediate1 = dataum.reduce((acc, curr) => {
Object.entries(curr).forEach(([k,v]) => {
if (k !== "id") {
if (!acc[k]) {
acc[k] = [];
}
acc[k].push(v);
}
});
return acc;
}, {});
console.log(intermediate1);
// {
// q1: [ 'yes', null, 'no', 'yes' ],
// q2: [ 4, 14, 83, 62 ],
// q3: [ null, 'medium', 'high', null ]
// }
const final = Object.entries(intermediate1).reduce((acc, [k, v]) => {
const accumulated = v.reduce((inner_acc, inner_val) => {
if (inner_val === null) {
inner_val = "empty";
}
if (!inner_acc[inner_val]) {
inner_acc[inner_val] = 0;
}
inner_acc[inner_val] += 1;
return inner_acc;
}, {});
acc.push({
[k]: accumulated,
});
return acc;
}, []);
console.log(final);
// [
// { q1: { yes: 2, empty: 1, no: 1 } },
// { q2: { '4': 1, '14': 1, '62': 1, '83': 1 } },
// { q3: { empty: 2, medium: 1, high: 1 } }
// ]
You may want to have a look into lodash, maybe they have something like that already.
Upvotes: 2