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:
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,
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
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.
CodePudding user response:
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.