1

I am trying to get a bunch (10-1500) of documents from firestore and then once I have them I check the amount I got, and then handle it from there.

I can only get this to work when I have a manual 'setTimeout' in between grabbing the docs and checking the array.

The array is not being filled with all of the firestore documents before I check for them but it is in an async function so I am confused to why it isn't waiting.

  • this is not a firestore issue, I receive all of the documents as I expect.

firestore

javascript async function

async function query(units, days){

  try {

    let allLogs = []

    var ts = moment().subtract(days,'days').valueOf() //ms timestamp from 1 -3 days ago


       await units.forEach(async(e) => {

         let ref = db.collection('units').doc(`${e.unit.superId}`).collection('logs').where('info.ms', '>=', parseInt(ts))

         let docs = await ref.get()  // get all subcollection documents from parent document

          await docs.forEach(async(doc) =>{ // Loop through and push all documents to allLogs array

             allLogs.push(doc.data())

           })
       })


     //If i dont add this: it will always think allLogs is empty. Not waiting long enough for it to be filled

     await new Promise(resolve => setTimeout(resolve, (days+ 1.5) * 1000 )); // x seconds wait for array to be filled


     if (allLogs.length > 0){
       console.log('filled')
     } else {
      console.log('empty')

     }


  } catch(err) {

    console.log(err)
  }


}

1 Answer 1

2

forEach does not await callbacks

It fires all calls sequentially and does not await them (it also return undefined, so awaiting it does nothing)

Use a for ... of loop to await each call

for (const unit of units) {
    let ref = db.collection('units').doc(`${unit.unit.superId}`).collection('logs').where('info.ms', '>=', parseInt(ts))
    let docs = await ref.get() // get all subcollection documents from parent document
    docs.forEach((doc) => { // Loop through and push all documents to allLogs array
        allLogs.push(doc.data())
    }
}

Or fire all promises and await all of them with Promise.all

await Promise.all(units.map(async (unit) => {
    let ref = db.collection('units').doc(`${unit.unit.superId}`).collection('logs').where('info.ms', '>=', parseInt(ts))
    let docs = await ref.get()  // get all subcollection documents from parent document
    docs.forEach((doc) => { // Loop through and push all documents to allLogs array
        allLogs.push(doc.data())
    })
}))

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Sign up to request clarification or add additional context in comments.

1 Comment

you just save my day : ) i was trying forEach() function but i now i realize to use for of function. agian very useful answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.