Say I am trying to create a "family tree" as one JSON array.
So I have an array of Person
objects.
Each Person
object has a mandatory name
. Each object can also optionally have a children
field that contains an array of other Person
objects (that also have a children
field - so the "depth" of the family tree can essentially go on forever.)
If there is no children, the children
field will just be an empty array []
.
E.g.
const family_name = "The Numbers";
const family = [{
name: "1"
children: [],
},
{
name: "2"
children: [{
name: "2 - 1",
children: [],
},
{
name: "2 - 2",
children: [{
name: "2 - 2 - 1",
children: [],
}, ],
}
],
},
{
name: "3"
children: [{
name: "3 - 1",
children: [],
}, ],
},
]
I need to POST the "parent" before the "child". When I POST a Person
, I get its id
back in the response.data
. This id
needs to be used in the immediate child's POST as a parent_id
so that child will be associated to the parent.
I also need to POST the "family_name" first which will return a family_id
. This family_id
will be used as the parent_id
for the very topmost Person
s only.
e.g.
axios.post(FAMILY_URL, {"family_name": family_name})
.then((response) => {
// Promise.all() POST 1, 2, and 3 with their "parent_id" as response.data.family_id
// Promise.all() POST 2-1 and 2-2 with their "parent_id" as 2's response.data.id
// POST 2-2-1 with its "parent_id" as 2-1's response.data.id
// POST 3-1 with its "parent_id" as 3's response.data.id
})
But what does the code look like if the number and depth of Person
objects is unknown? I have to leverage a recursive function, right?
I would also like to use Promise.all() for all "siblings"
CodePudding user response:
I would approach it using the BFS algorithm. Example:
function postFamily(family) {
const queue = [];
queue.unshift(...family);
while (queue.length) {
const cur = queue.pop();
// HERE IS YOUR LOGIC RELATED TO THE CURRENT NODE
// FOR EXAMPLE:
axios.post('*FAMILY URL*', cur);
for (const child of cur) {
queue.unshift(child);
}
}
}
I don't clearly understand the wanted result, but i'm glad if it would help. Have a nice day!
CodePudding user response:
You want to recursively walk the data structure, accumulating promises along the way
// fake axios, ignore this bit
const FAMILY_URL = "family-url"
const axios = {
post: async (url, data) => (console.log("post", data), {
data: {
id: `${url === FAMILY_URL ? "" : `${data.parent_id}-`}${Math.ceil(Math.random() * 100)}`
}
})
}
// resolves an individual person by posting their details with a given
// parent ID, then doing the same for any children
const savePerson = async (parent_id, { name, children }) => {
// get this person's ID
const { data: { id } } = await axios.post("person-url", {
name,
parent_id
})
return {
id, // assign the ID for visibility
name,
// pass this person's ID as the children's parent
children: await savePeople(id, children)
}
}
// resolves an array of people given a "parent ID"
const savePeople = (parent_id, people) =>
Promise.all(people.map(person => savePerson(parent_id, person)))
// Top-level family helper
const saveFamily = async (family_name, family) => {
const { data: { id } } = await axios.post(FAMILY_URL, { family_name })
// resolve all the people in the family array
return savePeople(id, family)
}
// minified
const family = [{"name":"1","children":[]},{"name":"2","children":[{"name":"2 - 1","children":[]},{"name":"2 - 2","children":[{"name":"2 - 2 - 1","children":[]}]}]},{"name":"3","children":[{"name":"3 - 1","children":[]}]}]
saveFamily("Smith", family).then(console.info)
.as-console-wrapper { max-height: 100% !important; }