I need to build a tree like structure using data from an API.
The structure i start with is as follows:
{
"type": "group",
"id": 1,
"name": "rootGroup",
"members": [],
}
There will always be a root group as the base of the tree.
I have a function named getMembersInGroup(groupId) which is an API call and returns something like:
[
{
"type": "group",
"id": 77,
"name": "IT group",
},
{
"type": "user",
"id": 40,
"name": "John"
}
]
Members can either be of type user or another group. So a user would look like:
{
"type": "user",
"id": 40,
"name": "John"
}
If it's another group it needs to recursively fetch those until there are only users or empty array left in members.
Any group can have users at any level with the tree.
A mock of getMembersInGroup:
const getMembersInGroup = async (groupId) => {
try {
const members = await fetch.callApi('/groups/' groupId '/members');
if (members) {
return members;
}
else {
return [];
}
} catch (error) {
return { error };
}
}
The end result should look like this:
{
"type": "group",
"id": 1,
"name": "rootGroup",
"members": [
{
"type": "group",
"id": 88,
"name": "Some group",
"members": [
{
"type": "user",
"id": 231,
"name": "SALLY"
},
{
"type": "user",
"id": 232,
"name": "Henry"
}
]
},
{
"type": "user",
"id": 41,
"name": "Chris"
}
],
}
I need help with the algorithm to create the tree.
CodePudding user response:
Your getMembersInGroup
function could look like this:
const getMembersInGroup = async (groupId) => {
const members = (await fetch.callApi(`/groups/${groupId}/members`)) ?? [];
for (const member of members) {
if (member.type == "group") {
member.members = await getMembersInGroup(member.id);
}
}
return members;
}
Call it like this:
async function loadTree() {
return {
type: "group",
id: 1,
name: "rootGroup",
members: await getMembersInGroup(1)
};
}
loadTree().then(result =>
console.log(result);
// Work with the result ...
).catch(error =>
console.log("error: ", error)
);
Demo with a mock implementation of fetch.callApi
:
// Mock for fetch.callApi
const fetch = {
mockData: [0,[2,3,4],[5,6,7],[8,9],0,0,0,[10],0,0,[11,12],0,0],
callApi(url) {
return new Promise((resolve, reject) => {
const groupId = url.split("/")[2];
const children = this.mockData[groupId];
if (!children) return reject("not found: " groupId);
const result = children.map(id => {
const type = this.mockData[id] ? "group" : "user";
return {type, id, name: type "_" id};
});
setTimeout(() => resolve(result), 50);
});
}
}
async function loadTree() {
return {
type: "group",
id: 1,
name: "rootGroup",
members: await getMembersInGroup(1)
};
}
const getMembersInGroup = async (groupId) => {
const members = (await fetch.callApi('/groups/' groupId '/members')) ?? [];
for (const member of members) {
if (member.type == "group") {
member.members = await getMembersInGroup(member.id);
}
}
return members;
}
loadTree().then(result =>
console.log(JSON.stringify(result, null, 2))
).catch(error =>
console.log("error: ", error)
);
CodePudding user response:
You can do something like:
const getMembersInGroup = async (groupId) => {
try {
const members = await fetch.callApi('/groups/' groupId '/members');
if (members) {
foreach(member in members) {
if (member.type == 'groups') {
member.members = getMembersInGroup(member.groupid)
}
}
return members;
}
else {
return [];
}
} catch (error) {
return { error };
}
}
So you have the recursion only if it's a group type, otherwise the member is returned as is.