Reputation: 83
I have parent-child JSON data and I want get all children (nested children) from selected parent.
For example, I have JSON data :
[{
"id": 1,
"parent": 0,
"name": "Parent"
}, {
"id": 2,
"parent": 1,
"name": "Child 1"
}, {
"id": 3,
"parent": 2,
"name": "Grand Child 1"
}, {
"id": 4,
"parent": 2,
"name": "Grand Child 2"
}, {
"id": 5,
"parent": 1,
"name": "Child 2"
}]
And I have function findAllChildren(1), where "1" is "parent" and then result of function should be :
[{
"id": 2,
"parent": 1,
"name": "Child 1"
}, {
"id": 3,
"parent": 2,
"name": "Grand Child 1"
}, {
"id": 4,
"parent": 2,
"name": "Grand Child 2"
}, {
"id": 5,
"parent": 1,
"name": "Child 2"
}]
And in other case, if i call findAllChildren(2), result of the function should like below :
[{
"id": 3,
"parent": 2,
"name": "Grand Child 1"
}, {
"id": 4,
"parent": 2,
"name": "Grand Child 2"
}]
What is the proper way to create function to solve that case? Thank you.
Upvotes: 8
Views: 28241
Reputation: 386620
I suggest to iterate all data and build a tree like object with properties to start the search with all given id
.
Then the object is walked and the children iterated for the result.
function getDescendant(id) {
var result = [];
Array.isArray(object[id].children) && object[id].children.forEach(function iter(a) {
result.push({ id: a.id, parent: a.parent, name: a.name });
Array.isArray(a.children) && a.children.forEach(iter);
});
return result;
}
var data = [{ id: 1, parent: 0, name: "Parent" }, { id: 2, parent: 1, name: "Child 1" }, { id: 3, parent: 2, name: "Grand Child 1" }, { id: 4, parent: 2, name: "Grand Child 2" }, { id: 5, parent: 1, name: "Child 2" }],
object = function (data, root) {
var o = {};
data.forEach(function (a) {
a.children = o[a.id] && o[a.id].children;
o[a.id] = a;
o[a.parent] = o[a.parent] || {};
o[a.parent].children = o[a.parent].children || [];
o[a.parent].children.push(a);
});
return o;
}(data, 0);
console.log(getDescendant(1));
console.log(getDescendant(2));
console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 2
Reputation: 2739
You can just iterate over the original data and look for items that has the specified id as parent_id. If found, do the same recursively with the element's id.
Check it out here: https://jsfiddle.net/6ydog1tj/2/
function findAllChildren (id, results, depth) {
for (d in data) {
if (data[d].parent == id) {
data[d].depth = depth
results.push(data[d])
findAllChildren(data[d].id, results, depth + 1)
}
}
}
var results = []
findAllChildren(1, results, 0)
$('body').append(results.map(function (element) { return Array(element.depth + 1).join(' -> ') + element.name + '<br>' }))
console.log(results)
prints out
Child 1
-> Grand Child 1
-> Grand Child 2
Child 2
Upvotes: 8
Reputation: 6282
You can use Array.prototype.filter
to remove items from an array that do not match a predicate condition.
filter
will loop over an array and run a function for each iteration. it the return value is true the item will be in the returned array.
The parentId
function passed into filter is curried. it will lock in the parent id you are searching for in the scope and return the function that filter will run.
const data = [{
"id": 1,
"parent": 0,
"name": "Parent"
}, {
"id": 2,
"parent": 1,
"name": "Child 1"
}, {
"id": 3,
"parent": 2,
"name": "Grand Child 1"
}, {
"id": 4,
"parent": 2,
"name": "Grand Child 2"
}, {
"id": 5,
"parent": 1,
"name": "Child 2"
}]
function parentId(id) {
return function(item) {
return item.parent === id
}
}
console.log(
data.filter(parentId(2))
)
Upvotes: 1