I am dealing with a complicated NoSQL database, and my goal is to parse the data within it, separate each level of childrens keys, and then use these keys to label columns on a grid. In this way I can visually show a documents Parent -> Child -> Child -> Child relationships.
It might be easier for my to describe the data and the task by showing the data and the expected output.
Please keep in mind this is mock data but the structure and the problem will be seen here.
[
{
"customer_id": 1,
"customer_name": "John",
"customer_phone": "720-222-1111",
"orders": [
{
"order_id": 1,
"total": 500,
"ordered_from": "website",
"products": [
{
"product_id": 1,
"product_price": 400,
"product_name": "The Blaster",
"product_description": "Blasts everyone away! Fun in the pool"
},
{
"product_id": 2,
"product_price": 100,
"product_name": "Water",
"product_description": "Average H20, delivered to your doorstep",
"product_attributes": [
{
"name": "Addon",
"color": "Blue"
}
]
}
]
},
{
"order_id": 2,
"total": 240,
"ordered_from": "app",
"geolocation": "California",
"coupon_code": "5X23A",
"products": [
{
"product_id": 2
}
]
}
]
},
{
"customer_id": 1,
"customer_name": "Alice",
"customer_address": "23 Main Street",
"customer_zipcode": "15234",
"orders": [
{
"order_id": 4,
"total": 100,
"ordered_from": "website",
"products": [
{
"product_id": 1,
"product_price": 100,
"product_name": "Fins",
"category": "Water"
}
]
},
{
"order_id": 2,
"total": 240,
"ordered_from": "app",
"geolocation": "California",
"coupon_code": "5X23A",
"products": [
{
"product_id": 2
}
]
}
]
},
{
"customer_id": 1,
"customer_name": "Colin",
"customer_gender": "Male",
"orders": [
{
"order_id": 1,
"total": 500,
"ordered_from": "website",
"products": [
{
"product_id": 1,
"product_price": 400,
"product_name": "The Blaster",
"product_description": "Blasts everyone away! Fun in the pool"
},
{
"product_id": 2,
"product_price": 100,
"product_name": "Water",
"product_description": "Average H20, delivered to your doorstep",
"product_attributes": [
{
"name": "Addon",
"color": "Blue"
}
]
}
]
},
{
"order_id": 2,
"total": 240,
"ordered_from": "app",
"geolocation": "California",
"coupon_code": "5X23A",
"products": [
{
"product_id": 2
}
]
}
]
}
]
Notice:
- Here we have three NoSql Documents, the parent level objects are customers
- the data within these objects are not standardized. One customer has a "customer_phone" key, while another doesnt. One customer has a "customer_address" key, while the other doesnt.
- The same point continues onto the next key of "orders" which is an array of also none-standardized objects. One order has a "geolocation" key, while the other doesn't.
- This non-standardization of data carries all the way down to the third child, "product_attributes", some products have this key, some don't.
My objects is to get every single possible key in every level of children.
So my expected output would be something like this.
Note: the value in this key:value pair doesn't matter at all. I am only using this object for the key, the value could be literally anything.
[
{
"KEY":"parent",
"customer_id":true,
"customer_phone":true,
"customer_zipcode":true,
"customer_address":true,
"customer_gender":true,
"customer_name":true,
"orders":true,
},
{
"KEY":"parent.orders",
"order_id":true,
"total":true,
"ordered_from":true,
"geolocation":true,
"coupon_code":true,
"products":true,
},
{
"KEY":"parent.orders.products",
"product_id":true,
"product_price":true,
"product_name":true,
"product_description":true,
"product_attributes":true,
"category":true,
},
{
"KEY":"parent.orders.products.attributes",
"name":true,
"color":true
}
]
Once I have this output, I could easily loop through it and use the keys to create columns on a grid component.
My attempt at a solution:
Pass the first shared JSON into this function
traverseTree(rawData: any, assembled: any[]): any {
let AllKeys: any = {};
let results = [];
rawData.forEach((question: any) => {
for (const [key, value] of Object.entries(question)) {
AllKeys[key] = value;
if (
Array.isArray(value) &&
value.length > 0 &&
typeof value[0] === 'object'
) {
console.log('Count ', value);
assembled = this.traverseTree(mockJSON.questionnaire, []);
}
}
});
results.push(AllKeys);
return [results, ...assembled];
}
If I remove the inner most if statement, I will get the expected results but ONLY for the parent, so i'll get the first object that I shared in my last JSON.
Another issue I have is that the data structure might change, and so I cannot predict how many levels of children there would be.
Thank you so much for anyone reading this, it's a real head splitter for me.
## Edit #2
New Output Data Structure
[
{
KEY: 'parent',
keys: [
'customer_id',
'customer_phone',
'customer_zipcode',
'customer_address',
'customer_gender',
'customer_name',
'orders',
],
data: [
{
'parent.primary_second': 'uuid-0001',
customer_id: 1,
customer_name: 'John',
customer_phone: '720-222-1111',
orders: [],
},
{
'parent.primary_second': 'uuid-1001',
customer_id: 1,
customer_name: 'Alice',
customer_address: '23 Main Street',
customer_zipcode: '15234',
},
{
'parent.primary_second': 'uuid-2001',
customer_id: 1,
customer_name: 'Colin',
customer_gender: 'Male',
orders: [],
},
],
},
{
KEY: 'parent.orders',
keys: [
'order_id',
'total',
'ordered_from',
'geolocation',
'coupon_code',
'products',
],
data: [
{
'sibling.primary_second': 'uuid-0001',
order_id: 1,
total: 500,
ordered_from: 'website',
'parent.orders.primary_second': 'uuid-0002',
},
{
'sibling.primary_second': 'uuid-0001',
order_id: 2,
total: 240,
ordered_from: 'app',
geolocation: 'California',
coupon_code: '5X23A',
'parent.orders.primary_second': 'uuid-0003',
},
{
'sibling.primary_second': 'uuid-1001',
order_id: 4,
total: 100,
ordered_from: 'website',
'parent.orders.primary_second': 'uuid-1002',
},
{
'sibling.primary_second': 'uuid-1001',
order_id: 2,
total: 240,
ordered_from: 'app',
geolocation: 'California',
coupon_code: '5X23A',
'parent.orders.primary_second': 'uuid-1003',
},
{
'sibling.primary_second': 'uuid-2001',
order_id: 1,
total: 500,
ordered_from: 'website',
'parent.orders.primary_second': 'uuid-2002',
products: [],
},
{
'sibling.primary_second': 'uuid-2001',
order_id: 2,
total: 240,
ordered_from: 'app',
geolocation: 'California',
coupon_code: '5X23A',
'parent.orders.primary_second': 'uuid-2003',
products: [
{
product_id: 2,
},
],
},
],
},
{
KEY: 'parent.orders.products',
keys: [
'product_id',
'product_price',
'product_name',
'product_description',
'product_attributes',
'category',
],
data: [
{
'sibling.orders.primary_second': 'uuid-0002',
product_id: 1,
product_price: 400,
product_name: 'The Blaster',
product_description: 'Blasts everyone away! Fun in the pool',
},
{
'sibling.orders.primary_second': 'uuid-0002',
product_id: 2,
product_price: 100,
product_name: 'Water',
product_description: 'Average H20, delivered to your doorstep',
'parent.orders.products.primary_second': 'uuid-0004',
},
{
'sibling.orders.primary_second': 'uuid-0003',
product_id: 2,
},
{
'sibling.orders.primary_second': 'uuid-1002',
product_id: 1,
product_price: 100,
product_name: 'Fins',
category: 'Water',
},
{
'sibling.orders.primary_second': 'uuid-1003',
product_id: 2,
},
{
'sibling.orders.primary_second': 'uuid-2002',
product_id: 1,
product_price: 400,
product_name: 'The Blaster',
product_description: 'Blasts everyone away! Fun in the pool',
},
{
'sibling.orders.primary_second': 'uuid-2002',
product_id: 2,
product_price: 100,
product_name: 'Water',
product_description: 'Average H20, delivered to your doorstep',
'parent.orders.products.primary_second': 'uuid-2004',
product_attributes: [],
},
],
},
{
KEY: 'parent.orders.products.attributes',
keys: ['name', 'color'],
data: [
{
'sibling.orders.primary_second': 'uuid-0004',
name: 'Addon',
color: 'Blue',
},
{
'sibling.orders.primary_second': 'uuid-2004',
name: 'Addon',
color: 'Blue',
},
],
},
];
What I changed was, now the keys are in an array as you mentioned. But in each object I also have the data associated with that object. And this data is linked Parent <---> Sibling via parent.x.primary_key and sibling.x.primary_key. I need these primary key links so that later I can show a nested view of Customer -> Order Related to Customer -> Product related to Order -> Attributes related to Product
I'm also open to changing up my data structure. This is the most complicated data structure and assignment i've had so I might not be seeing the problem for the whole.
To give a scope of the final expected result.
I'll have a grid showing all the customers.
When I click on one customer, a second grid will show up below the first, showing the selected customers related orders. When clicking an order, a third grid will show up showing the customers related products. And so on.
Visual Representation of Graphs:

Current Attempt at solution:
parseNestedData(data: any, parent: string) {
var result: any = {};
function do_level(arr: any, name?: any, primary_key?: any) {
const newUUID = UUID.UUID();
name = name || parent;
var level: any = {
KEY: name,
allValues: [],
};
let tempAllValues: any[] = [];
if (result[name]) level.allValues = [...result[name].allValues];
arr.forEach(function (obj: any, index: number) {
const valueExists = level.allValues.findIndex(
(v: any) => v.key === obj.key
);
tempAllValues.push({
...obj,
});
Object.keys(obj).forEach(function (key) {
var value = obj[key];
if (
Array.isArray(value) &&
typeof value === 'object' &&
typeof value[0] === 'object' &&
value !== null
) {
do_level(value, name + '.' + key, primary_key);
}
level[key] = true;
});
});
level.allValues = [
...level.allValues,
{ [name + '.primary_key']: newUUID, data: tempAllValues },
];
result[name] = Object.assign({}, result[name], level);
}
do_level(data);
return Object.values(result);
}