Reputation: 41
I have an API that returns a Parent Child relationship with multiple records
First call to API http://someAPI/getResult/?parent=null will give me:
{
ParentID: null,
Id: 1,
Name: 'Top Level Element'
}
Second call should be to http://someAPI/getResult/?parent=1 and that will return:
[
{
ParentID: 1,
ID: 2,
Name: 'Second Level Element First Element'
},
{
ParentID: 1,
ID: 3,
Name: 'Second Level Element Second Element'
}
]
The next should be http://someAPI/getResult/?parent=2 and then http://someAPI/getResult/?parent=3. Those will return their own children until finally no children are returned.
How can I write a recursive function that will retrieve all entries from the top level (ParentID = null) until the last child (no further records)?
Upvotes: 0
Views: 952
Reputation: 135377
Mutual recursion is a great way to build trees -
const fetchJson = (url = "") =>
fetch(url).then(r => r.json())
const getResult = (parent = null) =>
fetchJson(`http://someAPI/getResult/?parent=${parent}`)
.then(children => Promise.all(children.map(getResultAux))) // <-- calls getResultAux
const getResultAux = async (t = {}) =>
({ ...t, children: await getResult(t.id) }) // <-- calls getResult
const result =
await getResult() // default parent = null
console.log(result)
[
{
parentId: null,
id: 1,
name: 'Top Level Element',
children:
[
{
parentId: 1,
id: 2,
name: 'Second Level Element First Element',
children: [ { ... }, { ... }, ... ]
},
{
parentId: 1,
id: 3,
name: 'Second Level Element Second Element',
children: [ ... ]
}
]
}
]
Upvotes: 3
Reputation: 169308
It might be simplest to handle the recursion with a manual stack.
As this is an async
function, it will return a Promise that should eventually resolve to an object containing the responses for each parent=
...
async function getTree() {
const idsToCheck = ["null"];
const results = {};
while (idsToCheck.length) {
const id = idsToCheck.shift();
if (results[id]) {
// We've already processed this node
continue;
}
const resp = await fetch("http://someAPI/getResult/?parent=" + id);
if (!resp.ok) throw new Error("response not ok");
const data = await resp.json();
results[id] = data;
data.forEach((child) => {
idsToCheck.push(child.Id);
});
}
return results;
}
(Another formulation that uses actual recursive function calls:
async function getTree() {
const results = {};
async function populateResults(id) {
if (results[id]) {
// We've already processed this node
return;
}
const resp = await fetch("http://someAPI/getResult/?parent=" + id);
if (!resp.ok) throw new Error("response not ok");
const data = await resp.json();
results[id] = data;
for (let child of data) {
await populateResults(results, child.Id);
}
}
await populateResults("null");
return results;
}
)
Upvotes: 3