Handling race conditions when updating data / promise on a loop?

Hey guys

I've got a query about a race condition I'm experiencing. Long story short, I want to update multiple firestore db records from an editable table then refresh the underlying data when that's done.

In more detail, when a user edits multiple rows the JS does the following:

  • loop through the changed records and update the main collection - this is updateDocument and it can be asynchonous
  • loop through to update another collection if a certain condition is met from the updated row - this is writeFirstMessage and can also be asynchronous
  • read the the DB collection to refresh the table - this is getLeadsForTable and needs to wait for the loops to finish

When the data refreshes at the end, sometimes all the updates are compete and sometimes they're not - I think that's because the loops haven't finished when I call the DB read.

I experimented with promises on the db writes within the loop but they seemed to significantly decrease performance probably because the asyncyronous loop became synchronous.

Here's my code, any pointers on how to make sure the loops have finished before triggering the final command would be much appreciated :raised_hands:


const toUpdate = table1.recordUpdates;
let Sender = select2.value;
let Profile = select1.value;
let Message = text1.value;
let Strategy = select4.value;

for (let record of toUpdate) {
            updateDocument.trigger({
              additionalScope: {
                document_id: record._id,
                document_object: record,
              },
            });
              if (record.firstMessage == true){
              writeFirstMessageDocument.trigger({
              additionalScope: {
                document_id: record._id,
                document_insta: record.insta,
                document_sender: Sender,
                document_profile: Profile,
                document_message: Message,
                document_strategy: Strategy
                },
                })
              }
          }
getLeadsForTable.trigger();

Hey @jimbo! I'm not sure if this is exactly what you're looking for, but maybe you could use parts of this logic.

In this query, I'm looping through and triggering targetQuery for each item. And I only let the JS query resolve once the looping is complete.

Then, we can add a success event handler to trigger a final query (e.g. getLeadsForTable). Would something like Promise.resolve() work for you in your example? :slight_smile:

let results = [] //array to store all the returns in

async function go() {
  for (let i = 0; i < 10; i++) {
    console.log("triggering " + i)
    var result = await   targetQuery.trigger({ 
    additionalScope: {key1:i},
    onFailure: ()=>{
       console.log("fail")
    },
    onSuccess: ()=>{
       console.log("success")
    }})
    results.push(result)
    if(i==9){
      return results
    }
  }
}

return Promise.resolve(go()) //only finish running this JS query once all these have returned