Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to structure a recursive async/await function for firestore in node.js

What I am trying to do:
I am trying to retrieve all comments and their replies from firestore (firebase database) using a recursive method. Here is the structure of the data:
enter image description here

What is the problem
The parent asynchronous function does not wait for the nested asynchronous function to complete.

getThread = async (req, res) => {
    // Getting comments belonging to thread
    const thread_document = await db.doc(`/Threads/${req.params.threadid}`).get()
    threadData = thread_document.data()
    threadData.threadid = thread_document.id
    const comment_query = await db.collection('Comments').where('threadid', '==', threadData.threadid).get()

    // Getting replies belonging to comments
    for (document of comment_query){
    let commentData = await getReplies(document.id)
    threadData.comments.push(commentData )
    }
  return res.json(threadData)
}

//Recursive function to retrieve replies
getReplies = async (id) => {
    let comment = await db.doc(`/Comments/${id}`).get()
    let commentData = comment.data()
  
    commentData.comment_replies = commentData.replies.map(idx => {
      // The parent async function does not wait for the the async function here to finish.
      // Placing a await keyword here will raise the error 'await is only valid in async functions and the top level bodies of modules' 
      return getReplies(idx)
    })
    console.log(commentData)
    return commentData
}

Given the following example,
enter image description here
Since the parent async function does not wait for the nested async function, the order of execution now is A -> B -> a, and a fails to be mapped into commentData and commentData for comment A would end up empty. Hence, I want to program to do A -> a -> B. To do so, I would like to place a await keyword just before the getReplies like

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

return await getReplies(idx)

but it will raise the error,

await is only valid in async functions and the top level bodies of modules.

Which is confusing as getReplies is already a async function. I’ve looked into other solutions in stackoverflow but I am not able to get the recursive function working. Any insights would be appreciated, thank you.

>Solution :

commentData.comment_replies = commentData.replies.map(idx => {
  // ...
  return getReplies(idx)
})

This map statement is going to create an array of promises, but not wait for those promises to finish. You should use Promise.all to combine them into a single promise, and then await that promise to get the array of comment replies:

const promises = commentData.replies.map(idx => {
  return getReplies(idx);
});
commentData.comment_replies = await Promise.all(promises);

Which is confusing as getReplies is already a async function.

You were getting that error because the function you’re inside is idx => { return getReplies(idx) }, which is not an async function. But putting an await in there is not a solution to your problem anyway.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading