Home > Net >  Sync Async POSTing nested parent-children objects to preserve the order
Sync Async POSTing nested parent-children objects to preserve the order

Time:10-17

I have a nested array of Person objects.

Each Person object has a mandatory name. Each Person 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-1-1",
            children: [],
          }, ],
        },
        {
          name: "2-2",
          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.

The topmost Person will need to have their parent_id be the family_name.

Each "level" needs to be POSTed asynchronously as my back-end needs to preserve the order. (Note: Calculating the order of the Person on the client-side and passing that value to the back-end is not a solution as Person is actually a MPTT model where the insertion order matters.)

E.g. 1 then 2 then 3

E.g. 2 then 2-1 then 2-2.

However, the nested Persons can be POSTed in sync. For example, once POSTing 2 returns with a 201 response, its "sibling" 3 and its "child" 2-1 can be POSTed at the same time.

How can I optimally POST all Persons in a nested array so that the order is preserved? Please note that I am using axios.

Edit: Here is some pseudo-code:

function postPersons(persons, parent_id) {
    // Async POST all objects in persons
    // e.g. POST 1 then 2 then 3 to family_name

    // For each successful POST, if person has children, 
    // async POST those children to that person
    // e.g. Once POST to 2 resolves, POST 2-1 then 2-2 to 2
    // e.g. Once POST to 3 resolves, POST 3-1 to 3

    // Repeat for all successful POSTs
    // e.g. Once POST to 2-1 resolves, POST 2-1-1 to 2-1

}

postPersons(family, family_name)

CodePudding user response:

Instead of using async/await for a sequential loop, I'd recommend to use a synchronous loop and accumulate two things separately:

  • the promise for the child that is processed sequentially (see here or there)
  • an array of promises for all the recursive calls, that will be Promise.all'd in the end

This ensures proper order as well as immediate propagation of errors.

So the code will look like

function postPersons(persons, parent_id) {
    const results = [];
    let chain = Promise.resolve();
    for (const person of persons) {
        chain = chain.then(() =>
            postSinglePerson(person, parent_id)
        );
        results.push(chain.then(result =>
            postPersons(person.children, result.id)
        ));
    }
    return Promise.all(results);
}
postPersons(family, family_name).then(() => console.log('Done'), console.error);
  • Related