Published: 07/14/2020
There comes a time in every developers life when they have to decide “Do I work towards the best solution or just ship what I have?”
Today was that day. I built all kinds of neat things, a SQL materialized view to process 1,400,000 records, not to mention an ETL process to import that data, but my HARDEST problem was trying to figure out how to build a tree. Yes, I’m a CS background and I’m not talking about a 2 leaf binary tree with integers, I’m really talking about a nested structure.
The problem
The SQL output a table result like this:
category_1 | category_2 | category_3 | category_4 |
---|---|---|---|
IT | Hardware | Servers | Dell |
IT | Software | Adobe | Design Software |
IT | Hardware | Laptops | Apple |
Office Supplies | Printer | Paper | Unclassified |
This is a very clean view; but the json looks like this:
[
{
"category_1": "IT",
"category_2": "Hardware",
"category_3": "Servers",
"category_4": "Dell"
},{
"category_1": "IT",
"category_2": "Hardware",
"category_3": "Laptops",
"category_4": "Apple"
},{
"category_1": "IT",
"category_2": "Software",
"category_3": "Adobe",
"category_4": "Design Software"
},{
"category_1": "Office Supplies",
"category_2": "Printer",
"category_3": "Paper",
"category_4": "Unclassified"
}
]
The JSON sucks. This is what I want my output to look like:
{
data: {
map: {
"IT": {
"Hardware": {
"Servers": [ "DELL" ],
"Laptops": [ "Apple" ]
},
"Software": {
"Adobe": [ "Design Software" ]
}
},
"Office Supplies": {
"Printer": {
"Paper": [ "Unclassified" ]
}
}
}
}
}
Not bad but a lot of work for 4 records; I could just hard code it, right? Remember that million records; I have about 400 categories of deepley nested like this.
How I solved it
To get that result, I looked at NPM modules, binary tree generation algorithms; I thought this is stupid easy; somebody has written an module for it. What I found had explicit child / parent relationships defined as IDs and they wouldn’t support a function to change anything. My Solution is stupid, infact I’m not posting all of it, but its something like this:
var map = {};
for(var item in list) {
if(map[item.category_1]) {
if(map[item.category_1][item.category_2]) {
if(map[item.category_1][item.category_2][item.category_3]) {
map[item.category_1][item.category_2][item.category_3].push(map[item.category_1][item.category_2][item.category_3][item.category_4]);
} else {
// ... build level 3 & 4
}
}else {
// build level 2,3 & 4
}
} else {
// build level 1, 2,3 & 4
}
}
Thats a big, nasty function call. All to get nesting? You’re crazy man, but then I remembered, it’s always better to ship OK but working code today rather then shipping “PERFECT” code next week. There you have it, ship ugly code man, sometimes you need to.