С помощью lodash вы можете решить эту проблему следующим кратким образом:
const data = [{ countryID: 12, country: "US", schoolID: 122, schoolZone: "Highlands", studentID: 142, studentName: "Mary" }, { countryID: 12, country: "US", schoolID: 122, schoolZone: "Highlands", studentID: 145, studentName: "John" }, { countryID: 14, country: "UK", schoolID: 222, schoolZone: "Leeds", studentID: 223, studentName: "Peter" } ];
const grp = (arr, key, field, group, o=0) => _(arr)
.groupBy(key)
.mapValues(x => ({
[key]: _.head(x)[key],
[field]: _.head(x)[field],
[group]: o
? _.map(x, s => _.pick(s, ['studentID', 'studentName']))
: grp(x, 'schoolID', 'schoolZone', 'students', 1)
}))
.values()
.value()
console.log(grp(data, 'countryID', 'country', 'schools'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Идея состоит в том, чтобы использовать рекурсивный подход, когда вы вызываете одну и ту же функцию группировки 2 раза.Внутри которого мы бы _.groupBy
и просто сделали бы _.mapValues
Теперь точно такая же идея с компактным кодом ES6 будет выглядеть так:
const data = [{ countryID: 12, country: "US", schoolID: 122, schoolZone: "Highlands", studentID: 142, studentName: "Mary" }, { countryID: 12, country: "US", schoolID: 122, schoolZone: "Highlands", studentID: 145, studentName: "John" }, { countryID: 14, country: "UK", schoolID: 222, schoolZone: "Leeds", studentID: 223, studentName: "Peter" } ];
const groupBy = (arr, k) => arr.reduce((r,c) => (r[c[k]] = [...r[c[k]] || [], c], r), {})
const pick = (obj, fields) => fields.reduce((r,f) => (r[f] = obj[f], r), {})
const grp = (arr, k, f, b, o=0) =>
Object.values(Object.values(groupBy(arr, k)).map(x => ({
[k]: x[0][k],
[f]: x[0][f],
[b]: o
? x.map(s => pick(s, ['studentID', 'studentName']))
: grp(x, 'schoolID', 'schoolZone', 'students', 1)
})))
console.log(grp(data, 'countryID', 'country', 'schools'))