Best way to iterate hierarchical JSON/JS data - javascript

I'm hitting some performance issues with various implementations of this...
Essentially, I have a dataset of around 1500 objects in the below form: -
{
"Id": "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3",
"ParentId": null,
"Name": "Main Location",
"Children": [
{
"Id": "3cb93d59-613c-4797-8858-bc3f31f6baa0",
"ParentId": "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3",
"Name": "Site A",
"Children": [
{
"Id": "a1fec942-b425-4307-905d-9e2a6f8730b3",
"ParentId": "3cb93d59-613c-4797-8858-bc3f31f6baa0",
"Name": "Location A1",
"Children": [
{
"Id": "5538e976-db1c-49c2-8cab-70aafc1e4e70",
"ParentId": "a1fec942-b425-4307-905d-9e2a6f8730b3",
"Name": "Location A1 a",
"Children": []
},
{
"Id": "6f5a536f-4b4f-4a10-b7ba-657d772d0588",
"ParentId": "a1fec942-b425-4307-905d-9e2a6f8730b3",
"Name": "Location A1 b",
"Children": []
}
]
}
]
},
{
"Id": "319db987-994d-45d5-9023-8f21b8a589cb",
"ParentId": "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3",
"Name": "Site B",
"Children": [
{
"Id": "f0c1f222-4118-4c07-b7be-30ff70fada03",
"ParentId": "319db987-994d-45d5-9023-8f21b8a589cb",
"Name": "Location B1",
"Children": [
{
"Id": "fe33043d-4cf2-498e-aa80-04848e109acb",
"ParentId": "f0c1f222-4118-4c07-b7be-30ff70fada03",
"Name": "Location B1 b",
"Children": []
},
{
"Id": "d92ae7d5-bc44-4e94-be75-0cda5a254664",
"ParentId": "f0c1f222-4118-4c07-b7be-30ff70fada03",
"Name": "Location B1 b",
"Children": [
{
"Id": "0a89ee4a-3b18-4772-baa3-fc0682d7053f",
"ParentId": "d92ae7d5-bc44-4e94-be75-0cda5a254664",
"Name": "Location B1 b Special Site...",
"Children": []
}
]
}
]
}
]
}
]
}
]
It has an unknown depth, as in the children can continue to exist on each object...
Firstly, I would love to know what would be the fastest way to search this to find one of the objects given an Id (GUID). I have tried all sorts, I've experimented with flattening it out and using ES6 .find() (instead of filter for singular results...), I've written a custom iterator that essentially starts at the top and works it's way through the children until a match is found... These solutions work, I'm just wondering if there's a trick I'm missing..?
One area this slows down is if I want to then climb the tree from the found object, so if I use the .find() approach, and I want to know all of it's parents, I then need to also find() each parent based on the ParentId...
Secondly, now this perhaps is a bit of a unique use case, but essentially, I populate a customised React Treeview in JS with this data, and in the treeview, each item has a checkbox... Once the user checks the box, I add the object Id attribute to a 'selected' array to track what has been selected and what hasn't...
Where this gets complicated, is I don't want to then select all of the parent items above it, but instead need to know their ids so I can store them in a 'partially selected' array to illustrate on the Treeview that they haven't been selected, but a child of it somewhere has... (I conditionally change the styling of the checkbox depending if it's a Selected or 'Partially Selected' checkbox...
This is the key area where the slowdown occurs, because the User might check only 3 or 4 checkboxes mid way down the tree, which will also check all of their children, and this these 'partially selected' ids need to be found for each 'fully' checked item in the tree...
Make sense? :-S
I'm wondering basically, is there some super duper fast way that people usually use when working with things like this or is the nature of it slow and that's that because I simply need to check each route individually..?
Thanks!

You could build a hash map and have a fast access to the wanted objects.
const
buildHashMap = (r, o) => {
r[o.Id] = o;
return o.Children
? o.Children.reduce(buildHashMap, r)
: r;
},
data = [{ Id: "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3", ParentId: null, Name: "Main Location", Children: [{ Id: "3cb93d59-613c-4797-8858-bc3f31f6baa0", ParentId: "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3", Name: "Site A", Children: [{ Id: "a1fec942-b425-4307-905d-9e2a6f8730b3", ParentId: "3cb93d59-613c-4797-8858-bc3f31f6baa0", Name: "Location A1", Children: [{ Id: "5538e976-db1c-49c2-8cab-70aafc1e4e70", ParentId: "a1fec942-b425-4307-905d-9e2a6f8730b3", Name: "Location A1 a", Children: [] }, { Id: "6f5a536f-4b4f-4a10-b7ba-657d772d0588", ParentId: "a1fec942-b425-4307-905d-9e2a6f8730b3", Name: "Location A1 b", Children: [] }] }] }, { Id: "319db987-994d-45d5-9023-8f21b8a589cb", ParentId: "411fc047-9d58-4faf-8da2-dfaf1fc3f3a3", Name: "Site B", Children: [{ Id: "f0c1f222-4118-4c07-b7be-30ff70fada03", ParentId: "319db987-994d-45d5-9023-8f21b8a589cb", Name: "Location B1", Children: [{ Id: "fe33043d-4cf2-498e-aa80-04848e109acb", ParentId: "f0c1f222-4118-4c07-b7be-30ff70fada03", Name: "Location B1 b", Children: [] }, { Id: "d92ae7d5-bc44-4e94-be75-0cda5a254664", ParentId: "f0c1f222-4118-4c07-b7be-30ff70fada03", Name: "Location B1 b", Children: [{ Id: "0a89ee4a-3b18-4772-baa3-fc0682d7053f", ParentId: "d92ae7d5-bc44-4e94-be75-0cda5a254664", Name: "Location B1 b Special Site...", Children: [] }] }] }] }] }],
hashmap = data.reduce(buildHashMap, {});
console.log(hashmap);

Had you tried a custom recursive function?
function findId(data, id) {
const { Id, Children } = data;
if(id === Id) return data;
if(! Children || Children.length === 0) return null;
for(let i = 0; i < Children.length; ++i) {
const ret = findId(Children[i], id);
if(ret) return ret;
}
return null;
}
Hope this helps.

Related

Adding data to a nested JSON object with children based on an array - Javascript/REACT

Hello stackoverflow community! I've been creating my own fullstack application for a while now, on the NEXTjs framework. This is going pretty well!! Unfortunately, I got stuck on a JSON import object for a treeview component. The treeview component must be populated using a specific nested structure, along with which treeview item should be selected on an initial render.
I managed to get the correct JSON object from the database, using a sql recursive tree function.
const jsonObject =
{
"id": "bfa3fdf8-4672-404e-baf5-0f9098a5705b",
"label": "main category 1",
"children": [
{
"id": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"label": "sub category 1.1",
"children": []
},
{
"id": "3f5e5cc7-f8b2-4d75-89e1-841c66d863e6",
"label": "sub category 1.2",
"children": [
{
"id": "903a727f-d94d-44ff-b2f6-a985fd167343",
"label": "sub category 1.2.1",
"children": []
},
{
"id": "fb344480-8588-4ce3-9662-f8e89069e4b4",
"label": "sub category 1.2.2",
"children": []
}
]
}
]
}
The problem is that this object, with categories needs to be updated with a 'checked: "true"' or 'checked: "false"' key value pair based on the existence in the referenceSelectedCategories array. And I don't know how to do this; maintaining the structure and object as needed.
const desiredOutputJsonObject =
{
"id": "bfa3fdf8-4672-404e-baf5-0f9098a5705b",
"label": "main category 1",
** "checked": "false",**
"children": [
{
"id": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"label": "sub category 1.1",
** "checked": "true",**
"children": []
},
{
"id": "3f5e5cc7-f8b2-4d75-89e1-841c66d863e6",
"label": "sub category 1.2",
** "checked": "false",**
"children": [
{
"id": "903a727f-d94d-44ff-b2f6-a985fd167343",
"label": "sub category 1.2.1",
** "checked": "false",**
"children": []
},
{
"id": "fb344480-8588-4ce3-9662-f8e89069e4b4",
"label": "sub category 1.2.2",
** "checked": "true",**
"children": []
}
]
}
]
}
const referenceSelectedCategories =
[
{
"categoryId": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"productId": "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
"Id": "f82b0f63-3f39-486c-9157-5c7683b8e3b2"
},
{
"categoryId": "fb344480-8588-4ce3-9662-f8e89069e4b4",
"productId": "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
"Id": "b2e8681b-eec4-404d-8f87-c6314db42e30"
}
]
I've read several stackoverflow questions, also searched for examples, but can't get it to work. Could someone help me out here?
Some extra information:
Code language I'm using is REACT on NEXTjs framework;
Treeview component could have a dept of max 5 levels;
The structure of the JSON object doesn't change, it's exactly as presented above.
The "id" in the JSON object corresponds to the "categoryId" in the array.
Do you need more information? :) Just ask, I'll provide you with the extra details!
Kind Regards,
Chris
A straight forward solution with recursive method. Done a quick test, working fine. If any issues found, please point it out.
const parentObj =
[
{
"categoryId": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"productId": "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
"Id": "f82b0f63-3f39-486c-9157-5c7683b8e3b2"
},
{
"categoryId": "fb344480-8588-4ce3-9662-f8e89069e4b4",
"productId": "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
"Id": "b2e8681b-eec4-404d-8f87-c6314db42e30"
}
]
const existingId = parentObj.map((item)=> (item.Id))
const childobj =
{
"id": "bfa3fdf8-4672-404e-baf5-0f9098a5705b",
"label": "main category 1",
"children": [
{
"id": "12e544bc-91b1-4e5d-bdbc-2163a5618305",
"label": "sub category 1.1",
"children": []
},
{
"id": "3f5e5cc7-f8b2-4d75-89e1-841c66d863e6",
"label": "sub category 1.2",
"children": [
{
"id": "903a727f-d94d-44ff-b2f6-a985fd167343",
"label": "sub category 1.2.1",
"children": []
},
{
"id": "f82b0f63-3f39-486c-9157-5c7683b8e3b2",
"label": "sub category 1.2.2",
"children": []
}
]
}
]
}
const childObj = [childobj]
const updateData=(obj)=> {
if(existingId.includes(obj.id)) obj['checked'] = true; else obj['checked'] = false
}
const traverse=(childObj)=> {
for(const obj of childObj) {
updateData(obj);
if(obj.children.length > 0) traverse(obj.children);
}
}
traverse(childObj);
Here you can ty this logic :
let desiredOutputJsonObject = {
id: "bfa3fdf8-4672-404e-baf5-0f9098a5705b",
label: "main category 1",
checked: false,
children: [
{
id: "12e544bc-91b1-4e5d-bdbc-2163a5618305",
label: "sub category 1.1",
checked: true,
children: [],
},
{
id: "3f5e5cc7-f8b2-4d75-89e1-841c66d863e6",
label: "sub category 1.2",
checked: false,
children: [
{
id: "903a727f-d94d-44ff-b2f6-a985fd167343",
label: "sub category 1.2.1",
checked: false,
children: [],
},
{
id: "fb344480-8588-4ce3-9662-f8e89069e4b4",
label: "sub category 1.2.2",
checked: true,
children: [
{
id: "fb344480-8588-4ce3-9662-f8e89069e4b9",
label: "sub category 1.2.2",
checked: false,
children: [],
},
],
},
],
},
],
};
let referenceSelectedCategories = [
{
categoryId: "12e544bc-91b1-4e5d-bdbc-2163a5618305",
productId: "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
Id: "f82b0f63-3f39-486c-9157-5c7683b8e3b2",
},
{
categoryId: "fb344480-8588-4ce3-9662-f8e89069e4b4",
productId: "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
Id: "b2e8681b-eec4-404d-8f87-c6314db42e30",
},
{
categoryId:"fb344480-8588-4ce3-9662-f8e89069e4b9",
productId: "efed1c38-391b-4b5a-a9f1-91f3faec5f44",
Id: "b2e8681b-eec4-404d-8f87-c6314db42e30",
},
];
let stack = [desiredOutputJsonObject];
while (stack.length) {
let desiredOutput = stack.pop();
if (desiredOutput.children) {
desiredOutput.children.forEach((node) => {
//get node whose id == category id
let result = referenceSelectedCategories.find(
(obj) => obj.categoryId === node.id
);
// while traversing if we get referenceSelectedCategories.categoryId ==desiredOutputJsonObject.id
if (result) {
node.checked = true;
}
// for traverse purpose
if (node.children.length) {
stack.push(node);
}
});
}
}
console.log(desiredOutputJsonObject);

How to add or update items in this multidimensional JSON?

Let's say we have some houses represented as JSON. Something like this:
[
{
"id": "1",
"code": "1",
"name": "Smith's",
"children": [
{
"id": "",
"code": "11",
"name": "Kitchen",
"children": [
{
"id": "",
"code": "111",
"name": "Sink",
"children": []
}
]
},
{
"id": "",
"code": "12",
"name": "Living Room",
"children": [
{
"id": "",
"code": "121",
"name": "Television",
"children": [
{
"id": "",
"code": "1211",
"name": "Panel buttons",
"children": [
{
"id": "",
"code": "12111",
"name": "Power button",
"children": []
},
{
"id": "",
"code": "12112",
"name": "Colors adjust button",
"children": []
}
]
},
{
"id": "",
"code": "1221",
"name": "Screen",
"children": []
}
]
}
]
}
]
},
{
"id": "2",
"code": "2",
"name": "Taylor's",
"children": [
// Here goes all house places and items like the example above
]
},
{
"id": "1",
"code": "1",
"name": "Wilson's",
"children": [
// Here goes all house places and items like the example above
]
}
]
Take notice that the "code" property, found in each item, is something to represent the "path" until that item, carrying its parents "code" property concatenated with its own position by incremental order. So the code "11" means house 1 and child 1. And 212 would be house 2, child 1, child 2. Also take notice that all items follow the same type. In other words, every item has a children that follows its own type. So, it could be infinite.
Now, I'd like to maintain these structure. Adding items, updating items and so on. Let's say we want to add a carpet in Smith's living room. We would go deep in the structure 2 levels, which are Smith's house (index 0 of the array) and living room (index 1 of the children array). And then add a carpet.
The problem is it won't be 2 levels in all cases. What if I wanted to add a bathroom? It would be level 1, alongside with kitchen in living room (the first children). What if I'd like to add a microwave in the kitchen and add to it buttons, display, etc?
I think I'm a recursive scenario where I have to visit all items and, if it is the one I'm looking to reach at, add/updated it.
I've tried following this example
I couldn't figure it out how to bring it to my case. though.
I appreciate if your contribution is in JavaScript, but feel free to represent it in other language in case you are better in other language =).
There are indeed some questions, like for instance what happens if you have more than 10 items as child and why do you need it?
And what happens if you remove any item on any level? will you recursively start updating all codes?
Nevertheless I gave it a go. In essence what I do in the code is first search for the parent (example: Kitchen) where you want to add it to and then add the new child item (example: Carpet) to it.
The search is a typical recursive search.
The child addition is a typical addition to an array.
For argument's sake I assumed that the fields code always exist and that children is always an array.
// Actual code is underneath the declaration of this array
let houseList = [
{
"id": "1",
"code": "1",
"name": "Smith's",
"children": [
{
"id": "",
"code": "11",
"name": "Kitchen",
"children": [
{
"id": "",
"code": "111",
"name": "Sink",
"children": []
}
]
},
{
"id": "",
"code": "12",
"name": "Living Room",
"children": [
{
"id": "",
"code": "121",
"name": "Television",
"children": [
{
"id": "",
"code": "1211",
"name": "Panel buttons",
"children": [
{
"id": "",
"code": "12111",
"name": "Power button",
"children": []
},
{
"id": "",
"code": "12112",
"name": "Colors adjust button",
"children": []
}
]
},
{
"id": "",
"code": "1221",
"name": "Screen",
"children": []
}
]
}
]
}
]
},
{
"id": "2",
"code": "2",
"name": "Taylor's",
"children": [
// Here goes all house places and items like the example above
]
},
{
"id": "1",
"code": "1",
"name": "Wilson's",
"children": [
// Here goes all house places and items like the example above
]
}
]
addChild(houseList,"11",{name:"Carpet" });
addChild(houseList,"1211",{name: "Volume Up Button"});
addChild(houseList,"1211",{name: "Volume Down Button"});
console.log('new houselist', houseList);
// child is just what you want to add and the parentCode refers to where you want to add it to
function addChild(houseList, parentCode, child) {
let parent = findInHouseList(houseList,parentCode,child);
let amountOfChildren = parent.children.length;
let newCodeName = parentCode +""+ (amountOfChildren+1);
child = {...{id: "", code: newCodeName, children: []}, ...child};
console.log('adding child ', child);
parent.children = [...parent.children, child];
}
function findInHouseList(houseList,code) {
for (let house of houseList) {
let foundElement = findElement(house,code);
if ( foundElement)
return foundElement;
}
}
function findElement(currentElement, code) {
if ( currentElement.code === code)
return currentElement;
if (currentElement.children?.length > 0)
{
for (let child of currentElement.children) {
let foundElement = findElement(child,code);
if ( foundElement)
return foundElement;
}
}
return null;
}
I decided to let the code manage the code names for new children. It seems the easiest.
What you're trying to do is updating a JSON value at a dynamic path.
This function will append a child to the item which holds the specified code.
You may add conditions to check if the item at the code is defined
function appendChild(houses, code, item) {
let path = code.split('')
let o = houses
for (let i = 0; i < path.length; i++) {
let n = path[i] - 1
o = o[n]["children"]
}
o.push(item)
return houses
}
However, you should start your code indexes at 0 and storing them inside the JSON is useless since they are simply the path to reach the item.

Keeping a consistent parentId/id relationship with a flatten function

Suppose I have a nested object list like this:
[{
"id": "a",
"name": "Object a",
"parentId": "root",
"children": [{
"id": "c",
"name": "Object c"
},{
"id": "d",
"name": "Object D",
"parentId": "a"
}]
}, {
"id": "b",
"name": "Object b",
"parentId": "root"
}]
The object anatomy is simple: id, name, children (if any) and parentId. I'm using this flatten function that turns the nested object
into a flat array:
function flatten(array) {
var result = [];
array.forEach(function (a) {
result.push(a);
if (Array.isArray(a.children)) {
result = result.concat(flatten(a.children));
}
});
return result;
}
The thing is that the parentId value is not always persistent for every object, and therefore when the object gets flattened into an array, it's possible to lose a parent & child object relationship.
I need the flatten method to rebuild the parentId value according to the object structure. And there's only one catch, if the object is not a child, then it should have a parentId of root.
Help is very much appreciated
If I follow correctly, you just want to flatten your structure into an array that maintains the parentId relationship inherent in the original tree. If so, then I believe this will do:
const flatten = (xs, parentId = 'root') =>
xs .flatMap (({children = [], id, ...rest}) => [
{id, ...rest, parentId},
... flatten (children, id)
])
const input = [{id: "a", name: "Object a", parentId: "root", children: [{id: "c", name: "Object c"},{id: "d", name: "Object D", parentId: "a"}]}, {id: "b", name: "Object b", parentId: "root"}]
console .log (flatten (input))
.as-console-wrapper {max-height: 100% !important; top: 0}
It's a fairly simple recursion, using flatMap to combine the records and parameter destructuring (with default a parameter for children) to simplify our object handling.
Sounds like you just need to add the parentId to the objects that don't have them. Change
result = result.concat(flatten(a.children));
to
result = result.concat(flatten(a.children.map(addParent(a.parentId)));
const addParent = parentId => item => ({ ...item, parentId });
where the root is called with a parentId of root.
You can pass the parentId in as the second argument to your flatten function like so, with the default parent just being "root".
const arr = [{
"id": "a",
"name": "Object a",
"parentId": "root",
"children": [{
"id": "c",
"name": "Object c"
},{
"id": "d",
"name": "Object D",
"parentId": "a"
}]
}, {
"id": "b",
"name": "Object b",
"parentId": "root"
}]
function flatten(array, parentId = "root") {
let result = [];
array.forEach(function(a) {
a.parentId = parentId;
result.push(a);
if (Array.isArray(a.children)) {
result = result.concat(flatten(a.children, a.id));
}
delete a.children; // optional
});
return result;
}
console.log(flatten(arr));

JavaScript: Solving an algorithmic problem

Today I was working on a problem, which states as follows:
Problem:
INPUT: [{..}, {..}, ..] Array of objects;
Each object is has {"id": required, "children": []}
The objects has parent-child relation based on "id" and "children" props
OUTPUT: [{..}, {..}, ..] Array in a tree (hierarchy) order :multi-level.
Input:
[{
"id": 1,
"name": "Earth",
"children": [2, 3]
}, {
"id": 2,
"name": "Asia",
"children": []
}, {
"id": 3,
"name": "Europe",
"children": [4]
}, {
"id": 4,
"name": "Germany",
"children": [5]
}, {
"id": 5,
"name": "Hamburg",
"children": []
}]
OutPut
[{
"id": 1,
"name": "Earth",
"children": [{
"id": 2,
"name": "Asia",
"children": []
}, {
"id": 3,
"name": "Europe",
"children": [{
"id": 4,
"name": "Germany",
"children": [{
"id": 5,
"name": "Hamburg",
"children": []
}]
}]
}]
}]
My approach
I decided to solve this by iterating through each element in the array and recursively find and append objects to children of each element.
So just to start with, I decided to have only First level children appended their respective parents. And my code is following.
var posts = [{"id":1,"name":"Earth","children":[2,3]},{"id":2,"name":"Asia","children":[]},{"id":3,"name":"Europe","children":[4]},{"id":4,"name":"Germany","children":[5]},{"id":5,"name":"Hamburg","children":[]}]
function getElementById (id, posts) {
for(var i =0; i< posts.length; i++){
if(posts[i].id === id){
var found = posts[i];
///// FUN here -> //// posts.splice(i, 1);
return found;
}
}
}
function refactorChildren(element, posts) {
if(!element.children || element.children.length === 0) {
return element;
}
var children = [];
for(var i = 0; i < element.children.length; i++){
var childElement = getElementById(element.children[i], posts);
children.push(childElement);
}
element.children = children;
return element;
}
function iterate(posts) {
var newPosts = [];
var des = [...posts]
for(var i = 0; i < des.length; i++){
var childedElement = refactorChildren(des[i], des);
newPosts.push(childedElement);
}
return newPosts;
}
var filtered = iterate(posts);
console.log(JSON.stringify(filtered))
Surprisingly above code Solves the ACTUAL PROBLEM (except a lil bit of more work)
My Expected Result should be the following: Array of objects with only First level children
[{
"id": 1,
"name": "Earth",
"children": [{
"id": 2,
"name": "Asia",
"children": []
}, {
"id": 3,
"name": "Europe",
"children": [4]
}]
}, {
"id": 4,
"name": "Germany",
"children": [{
"id": 5,
"name": "Hamburg",
"children": []
}]
}]
And I do get the above result if I uncomment the ///// FUN here -> //// line. Which is erasing the iterating object on the go.
So my problem is
I want to know - HOW DID? All the objects got appended correctly to their respective Parent objects by that code? My next step was to add a recursion call to the function refactorChildren(with-childElement).
AND
How did, just by adding posts.splice(i, 1); got me MY expected result from the code?
Please help me understand, I just cant go ahead without knowing "HOW".
Thanks
While traversing the objects, you recursively call a function on all its chilfren and remove the objects from the array:
[
{ id: 1, children: [2], }, // < iterator
{ id: 2, children: [] }, // < gets spliced out recursively
]
If a child is in the array before its parent however, this won't work as you copy the child into another array before the parent gets visited.
Maybe you are interested in a different approach with only a single loop for getting the parent elements and their children.
This works for unsorted data, too.
var data = [{ id: 1, name: "Earth", children: [2, 3] }, { id: 2, name: "Asia", children: [] }, { id: 3, name: "Europe", children: [4] }, { id: 4, name: "Germany", children: [5] }, { id: 5, name: "Hamburg", children: [] }],
tree = function (array) {
var r = {},
children = new Set,
result = [];
array.forEach(o => {
Object.assign(
r[o.id] = r[o.id] || {},
o,
{ children: o.children.map(id => (children.add(id), r[id] = r[id] || {})) }
);
});
return Object.values(r).filter(({ id }) => !children.has(id));
}(data);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Getting Specific data from Nested Json which is having multiple Parent Children

Am trying to filter out some specific data's from Nested JSON which is having multiple Parent Children . Here is my json ,
[{
"id": "111111",
"name": "Parent",
"steps": [{
"id": "22222",
"name": "Child",
"steps": [{
"id": "333333",
"name": "Child -Child",
"steps": [{
"id": "444444",
"name": "Child - Child - Child",
"steps": [{
"id": "5555",
"name": "Child - Child - Child - Child"
}, {
"id": "522e9327-0747-4080-b6e2-d57e726b5b26",
"name": "Child - Child - Child - Child 2"
}],
}],
}],
}],
}]
What am trying to do here is i have to get some specific data's which are inside this nested json . For Ex : i need output like ["parent","Child","Child-Child"...etc ] . So i used map function using java script but the output was different like this one ["ParentChildChildChild"] (With No spaces) .If output's are String only mean's i can put "\n" and separate them but sometimes they are in Numbers so problem will occur's . Here is my Code which i tried ,
var myReturnedValues = mainSteps.map(x => [
x.steps.map(y => y.name +
y.steps.map(z => z.name +
z.steps.map(a => a.name + a.steps.map(b => b.name))
)
)
]);
Can someone help/clarify Me .
To achieve this most effectively you need To achieve this most effectively you need To achieve this most effectively you need to use recursion use recursion use recursion.
Using this pattern means that the array will always be filled no matter how many levels of nested object you have. Try this:
var data = [{
"id": "111111",
"name": "Parent",
"steps": [{
"id": "22222",
"name": "Child",
"steps": [{
"id": "333333",
"name": "Child -Child",
"steps": [{
"id": "444444",
"name": "Child - Child - Child",
"steps": [{
"id": "5555",
"name": "Child - Child - Child - Child"
}, {
"id": "522e9327-0747-4080-b6e2-d57e726b5b26",
"name": "Child - Child - Child - Child 2"
}],
}],
}],
}],
}]
var names = [];
function getNames(arr) {
for (var i = 0; i < arr.length; i++) {
names.push(arr[i].name);
if (arr[i].steps && arr[i].steps.length)
getNames(arr[i].steps);
}
}
getNames(data);
console.log(names);
You can achieve this using the javascript map function & recursion
var jsonArray = [{
"id": "111111",
"name": "Parent",
"steps": [{
"id": "22222",
"name": "Child",
"steps": [{
"id": "333333",
"name": "Child -Child",
"steps": [{
"id": "444444",
"name": "Child - Child - Child",
"steps": [{
"id": "5555",
"name": "Child - Child - Child - Child"
}, {
"id": "522e9327-0747-4080-b6e2-d57e726b5b26",
"name": "Child - Child - Child - Child 2"
}],
}],
}],
}],
}]
var namesArray = [];
var recur = function(obj) {
namesArray.push(obj.name);
if(obj.steps) {
obj.steps.map(recur);
}
}
jsonArray.map(recur);
console.log(namesArray);
You can also try
function getObjectKeyValues(obj, objKey) {
var result = [];
JSON.stringify(obj, function(key, value) {
if (key === objKey) {
result.push(value)
}
return;
});
return result;
}
Check:
MDN JSON.stringify()

Categories