I have an array that is used to track status of certain documents. This looks like the following when outputted from a Mongo Aggregate function. k
is the status, and v
is the count of documents with this status.
[
{
"legal": [
{ "k": "", "v": 6 },
{ "v": 3},
{ "k": "To be uploaded", "v": 5 },
{ "k": "To be reviewed", "v": 96 }
],
"operations": [
{ "v": 1 },
{ "k": "To be uploaded", "v": 3 },
{ "k": "To be reviewed", "v": 24 }
],
"accounting": [
{ "k": "To be reviewed", "v": 137 },
{ "k": "", "v": 3 },
{ "v": 2 },
{ "k": "To be uploaded", "v": 24 },
{ "k": "Not Required", "v": 1 }
]
}
]
I want to graph these on a stacked bar chart, and require the following format. The data array is in the order ["legal", "operations", "accounting"]
[
{
name: "", // no status specified
data: [9, 1, 5]
},
{
name: "To be uploaded",
data: [5, 3, 24]
},
{
name: "To be reviewed",
data: [96, 24, 137]
},
{
name: "Not Required",
data: [0, 0, 1]
},
]
CodePudding user response:
One approach would be to use a combination of Array#map
and Array#reduce
methods as follows. Array#reduce
would be great at creating a summary of and cleaning up the data object, while Array#map
would help with the final presentation. It can be improved upon, of course:
const input = [ { "legal": [ { "k": "", "v": 6 }, { "v": 3}, { "k": "To be uploaded", "v": 5 }, { "k": "To be reviewed", "v": 96 } ], "operations": [ { "v": 1 }, { "k": "To be uploaded", "v": 3 }, { "k": "To be reviewed", "v": 24 } ], "accounting": [ { "k": "To be reviewed", "v": 137 }, { "k": "", "v": 3 }, { "v": 2 }, { "k": "To be uploaded", "v": 24 }, { "k": "Not Required", "v": 1 } ] } ],
summary = input.map(
({legal,operations,accounting}) =>
({
legal:legal.reduce((acc,{k,v}) => ({...acc,[k || "NONE"]:(acc[k || "NONE"] || 0) v}),{"Not Required":0}),
operations:operations.reduce((acc,{k,v}) => ({...acc,[k || "NONE"]:(acc[k || "NONE"] || 0) v}),{"Not Required":0}),
accounting:accounting.reduce((acc,{k,v}) => ({...acc,[k || "NONE"]:(acc[k || "NONE"] || 0) v}),{"Not Required":0})
})
),
output = summary
.flatMap(
o => Object.keys(Object.values(o)[0])
.map(
z => ({
name: z === "NONE" ? "" : z,
data: Object.keys(o).map(y => o[y][z])
})
)
);
console.log( output );
Alternatively .....
You can create summary
dynamically as follows:
const input = [ { "legal": [ { "k": "", "v": 6 }, { "v": 3}, { "k": "To be uploaded", "v": 5 }, { "k": "To be reviewed", "v": 96 } ], "operations": [ { "v": 1 }, { "k": "To be uploaded", "v": 3 }, { "k": "To be reviewed", "v": 24 } ], "accounting": [ { "k": "To be reviewed", "v": 137 }, { "k": "", "v": 3 }, { "v": 2 }, { "k": "To be uploaded", "v": 24 }, { "k": "Not Required", "v": 1 } ] } ],
summary = input.flatMap(
o =>
Object.keys(o)
.reduce(
(ac,cat) =>
({
...ac,
[cat]:o[cat].reduce((acc,{k,v}) => ({...acc,[k || "NONE"]:(acc[k || "NONE"] || 0) v}),{"Not Required":0})
}),{}
)
),
output = summary
.flatMap(
o => Object.keys(Object.values(o)[0])
.map(
z => ({
name: z === "NONE" ? "" : z,
data: Object.keys(o).map(y => o[y][z])
})
)
);
console.log( output );