I am looking the following example lodash - group and populate arrays.
However I need to group by multi times like following example. What should I do? Thanks
[
{ birthdate: "1993", day: "12", category: "a", name: "Ben" },
{ birthdate: "1993", day: "13", category: "a", name: "John" },
{ birthdate: "1993", day: "14", category: "b", name: "Larry" },
{ birthdate: "1994", day: "15", category: "", name: "Nicole" },
];
to
[
{
birthdate: "1993",
birthdateDetail: [
{
category: "a",
categoryDetail: [
{ day: "12", name: "Ben" },
{ day: "13", name: "John" },
],
},
{
category: "b",
categoryDetail: [{ day: "14", name: "Larry" }],
},
],
},
{
birthdate: "1994",
birthdateDetail: [{ category: "", day: "15", name: "Nicole" }],
},
];
You could groups with an abstract approach for nested grouping by taking an object which keeps the keys for each level as well as the wanted result structure.
This approach works for arbitrary nesting.
const
data = [{ birthdate: "1993", day: "12", category: "a", name: "Ben" }, { birthdate: "1993", day: "13", category: "a", name: "John" }, { birthdate: "1993", day: "14", category: "b", name: "Larry" }, { birthdate: "1994", day: "15", category: "", name: "Nicole" }],
groups = ['birthdate', 'category'],
getEmpty = () => ({ _: [] }),
result = data
.reduce((q, o) => {
groups
.reduce((r, k) => {
const v = o[k];
if (!v) return r;
if (!r[v]) r._.push({ [k]: v, [k + 'Detail']: (r[v] = getEmpty())._ });
return r[v];
}, q)
._
.push(o);
return q;
}, getEmpty())
._;
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You're in the right direction: using _.groupBy
will help you to group your data, but since you need two levels of nesting, you will need to run it twice:
birthdate
category
Since _.groupBy
returns an object, we will need to use Object.entries
to transform the key-value pair into an array of objects that fit the shape you have intended.
At the second level, we will need to do a final iteration to ensure that we remove the category
and birthday
keys from the nested data.
See proof-of-concept below:
const data = [
{ birthdate: "1993", day: "12", category: "a", name: "Ben" },
{ birthdate: "1993", day: "13", category: "a", name: "John" },
{ birthdate: "1993", day: "14", category: "b", name: "Larry" },
{ birthdate: "1994", day: "15", category: "", name: "Nicole" },
];
// Top level: group by birthdate
const dataByBirthdate = _.groupBy(data, d => d.birthdate);
// Convert object into array of objects
const transformedData = Object.entries(dataByBirthdate).map(entry => {
const [birthdate, value] = entry;
// Second level: group by category
const birthdatedetailByCategory = _.groupBy(value, d => d.category);
const birthdatedetail = Object.entries(birthdatedetailByCategory).map(entry => {
const [category, value] = entry;
// Step through all entries to ensure we remove keys of your selection
const categorydetail = value.map(d => {
delete d.birthdate;
delete d.category;
return d;
});
return { category, categorydetail };
});
return { birthdate, birthdatedetail };
});
console.log(transformedData);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
This is function to group array with lodash:
const formatedResponse = _(arr)
.groupBy("birthdate")
.map((items, birthdate) => {
const birthdateDetails = _(items)
.groupBy("category")
.map((items, category) => {
return {
category,
categoryDetails: items.map(({ day, name }) => ({ day, name }))
};
})
.value();
return {
birthdate,
birthdateDetails
};
})
.value();