Original data looks like that:
let AddressesBook = [
{
"userName": "Jay12",
"doorNumber": "1512",
"cityID": 19,
"city": "London",
"countryID": 1,
"country": "UK",
"houseType": "private"
},
{
"userName": "Jay12",
"doorNumber": "2003",
"cityID": 14,
"city": "York",
"countryID": 1,
"universe": "UK",
"houseType": "private"
},
{
"userName": "Jay12",
"doorNumber": "435",
"cityID": 31,
"city": "Washington",
"countryID": 2,
"universe": "USA",
"houseType": "private"
},
{
"userName": "Jay12",
"doorNumber": "1123",
"cityID": 18,
"city": "Oxford",
"countryID": 1,
"universe": "UK",
"houseType": "private"
}
];
i was mapping the data hierarchy by relevant unique ID using Lodash and a suppurated dictionary:
function nestMaker(list, order) {
if (_.isEmpty(order)) return [];
let groups = _.groupBy(list, _.first(order));
return _.map(groups, (children, key) => {
let group = {};
group[_.first(order)] = key;
group.data = nestMaker(children, _.drop(order));
return _.isEmpty(group.data) ? _.omit(group, 'data') : group;
});
}
let hierarchical = nestMaker(AddressesBook, [
"countryID",
"cityID",
"houseType",
"doorNumber"]
);
it works fine, but i would like to have the name relevant to the id in each level of the object. unfortunately you can't use _.groupBy on two keys. i was thinking about using _.unionWith separately from the first iteration but i couldn't find a way to use it recursively omitting the unnecessary data.
expected output:
let output =
[
{
"countryID": "1",
"country": "UK",
"data": [
{
"cityID": "14",
"city": "York",
"data": [
{
"houseType": "private",
"data": [
{
"doorNumber": "2003"
}
]
}
]
},
{
"cityID": "18",
"city": "Oxford",
"data": [
{
"houseType": "private",
"data": [
{
"doorNumber": "1123"
}
]
}
]
},
{
"cityID": "19",
"city": "London",
"data": [
{
"houseType": "private",
"data": [
{
"doorNumber": "1512"
}
]
}
]
}
]
},
{
"countryID": "2",
"country": "USA",
"data": [
{
"cityID": "31",
"city": "Washington",
"data": [
{
"houseType": "private",
"data": [
{
"doorNumber": "435"
}
]
}
]
}
]
}
];
You can get the 1st item in the group, and extract the name (country, city) from the item:
const AddressesBook = [{"userName":"Jay12","doorNumber":"1512","cityID":19,"city":"London","countryID":1,"country":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"2003","cityID":14,"city":"York","countryID":1,"country":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"435","cityID":31,"city":"Washington","countryID":2,"country":"USA","houseType":"private"},{"userName":"Jay12","doorNumber":"1123","cityID":18,"city":"Oxford","countryID":1,"country":"UK","houseType":"private"}];
const nestMaker = (list, order) => {
if (_.isEmpty(order)) return [];
const idKey = _.first(order);
const nameKey = idKey.replace('ID', '');
let groups = _.groupBy(list, idKey);
return _.map(groups, (children, key) => {
const group = {};
const child = _.first(children);
group[idKey] = key;
if(_.has(child, nameKey)) group[nameKey] = child[nameKey];
group.data = nestMaker(children, _.drop(order));
return _.isEmpty(group.data) ? _.omit(group, 'data') : group;
});
}
const hierarchical = nestMaker(AddressesBook, [
"countryID",
"cityID",
"houseType",
"doorNumber"
]);
console.log(hierarchical);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
If the id and the name keys are doesn't follow the same pattern, you can explicitly state them as entry in the order:
const AddressesBook = [{"userName":"Jay12","doorNumber":"1512","cityID":19,"city":"London","countryID":1,"universe":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"2003","cityID":14,"city":"York","countryID":1,"universe":"UK","houseType":"private"},{"userName":"Jay12","doorNumber":"435","cityID":31,"city":"Washington","countryID":2,"universe":"USA","houseType":"private"},{"userName":"Jay12","doorNumber":"1123","cityID":18,"city":"Oxford","countryID":1,"universe":"UK","houseType":"private"}];
const nestMaker = (list, order) => {
if (_.isEmpty(order)) return [];
const entry = _.first(order);
const [idKey, nameKey] = Array.isArray(entry) ? entry : [entry];
let groups = _.groupBy(list, idKey);
return _.map(groups, (children, key) => {
const group = {};
const child = _.first(children);
group[idKey] = key;
if(_.has(child, nameKey)) group[nameKey] = child[nameKey];
group.data = nestMaker(children, _.drop(order));
return _.isEmpty(group.data) ? _.omit(group, 'data') : group;
});
}
const hierarchical = nestMaker(AddressesBook, [
["countryID", "universe"],
["cityID", "city"],
"houseType",
"doorNumber"
]);
console.log(hierarchical);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>