0

Currently, I am querying for objects in the database to update. A snippet of the function that does so is

 return getPostsForDate.get().then(snapshot => {
        const updates = {}
        var counter = 0
        const batch = admin.firestore().batch()
        snapshot.forEach((doc) => {

            var key = doc.id
            return admin.database().ref('/convoID/' + key).once('value', (snapshot) => {
                if (snapshot.exists()) {
                    const convoIDCollection = snapshot.val()
                    for (var child in convoIDCollection) {

                        console.log(child)
                        updates["conversations/" + child] = null
                        updates["messages/"+ child] = null
                        updates["convoID/"+ child] = null
                    }
                }
                updates["/convoID/" + key] = null
                updates["/reveals/" + key] = null
                updates["/postDetails/" + key] = null
                const postFireStoreRef = admin.firestore().collection('posts').doc(key)
                const posterRef = admin.firestore().collection('posters').doc(key)
                batch.delete(postFireStoreRef)
                batch.delete(posterRef)
                counter++
                console.log(counter)
             })

        })
        if (counter > 0) {
            console.log("at the deletion point")
              return Promise.all[admin.database().ref().update(updates), batch.commit()] 
        }
        else {
            console.log("null")
            return null
        }
})

Essentially, after the firestore queries for the posts, additional details are received from the realtime database and added to an array. Finally, I commit all these updates through a promise. However, the function that returns the updates is never reached - in order to ensure that updates are needed to the database, I have a counter that counts the number of updates. If it is greater than 0, I return

 return Promise.all[admin.database().ref().update(updates), batch.commit()]

However, it seems like the return function is executed before the additional details are received, as it keeps on returning "null" to the console log which should only happen if the counter is less than 0.

Essentially, how do I wait for the data to be queried before executing the updates?

Update

    return getPostsForDate.get().then(snapshot => {
    const updates = {} 
    const promises = []
    var counter = 0
    const batch = admin.firestore().batch()
    snapshot.forEach((doc) => {
 promises.push (
        admin.database().ref('/convoID/' + key).once('value', (snapshot) => {
            if (snapshot.exists()) {
                const convoIDCollection = snapshot.val()
                for (var child in convoIDCollection) {
                    updates["conversations/" + child] = null
                    updates["messages/"+ child] = null
                    updates["convoID/"+ child] = null
                }
            }
            updates["/convoID/" + key] = null
            updates["/reveals/" + key] = null
            updates["/postDetails/" + key] = null
            const postFireStoreRef = admin.firestore().collection('posts').doc(key)
            const posterRef = admin.firestore().collection('posters').doc(key)
            batch.delete(postFireStoreRef)
            batch.delete(posterRef)
            counter++
         })
        )
    })
    Promise.all(promises).then(() => {
    if (counter > 0) {
        console.log("at the deletion")
          return Promise.all[admin.database().ref().update(updates), batch.commit()] 
    }
    else {
        console.log("null")
        return null
    }
})
})
})

1 Answer 1

1

admin.database().ref('/convoID/' + key).once(...) is asynchronous and returns a promise, but your code isn't using those promises to wait for each query to complete. This means your code is moving on to the if/else immediately after the snapshot iteration, but before counter is ever updated, or the batches are added.

You'll need to restructure your code to collect all those promises from once() into an array, use Promise.all() to wait for all those promises to resolve, then commit the batch.

9
  • appreciate the fast response. How exactly would I collect the promises? Would I make it into a .then(snapshot) and return all the batch deletes? Something like .once('value').then(snapshot => { and combine that with return [updates]? Commented Jul 28, 2018 at 3:27
  • 1
    stackoverflow.com/questions/38362231/… Commented Jul 28, 2018 at 3:32
  • The link was extremely helpful; however, I tried implementing it as in my answer update and I am now receiving Each promise should return a value and Expected catch or return And Avoid nesting promises I created the array of promises; however, I need to return them. How can I return them while also returning from the return getPostsForDate.get().then(snapshot => { Sorry if the solution is obvious, appreciate your time. Commented Jul 28, 2018 at 3:40
  • sorry, that comment may have been too broad. Instead, would I need to do use promise.all for the conversations or for each document? As you can see, I do snapshot.forEach(doc) AND for (var child in convoIDCollection) { Commented Jul 28, 2018 at 4:06
  • I'm not sure how it would be helpful in the latter, as it's doing no async work. Commented Jul 28, 2018 at 4:13

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.