我的应用程序在Firebase Firestore中包含带有嵌套评论的帖子,其结构使得每个带有docID
的帖子/评论都有一个子集合postComments
。因此,给定的帖子/评论可以有无限数量的嵌套评论。
comments
- docID
postComments
- docID
- docID
- docID
- docID
postComments
- docID
- docID
我目前正在编写一个Firebase云函数,以递归方式查询给定docID
的所有文档和子集合文档,并在数组中返回所有这些文档。我的计划是定义getChildComments
异步函数,该函数接收docID
并返回该文档的postComments
子集合中的所有文档。然后,我会递归地调用getChildComments
,直到我用线程中的所有嵌套注释构建了一个数组。
exports.loadWholeCommentThread = functions.https.onCall(async (data, context) => {
let comments = await getChildComments(data.rootID);
return comments;
});
async function getChildComments(docID) {
try {
const db = admin.firestore();
const commentsRef = db.collection('comments').doc(docID).collection('postComments');
var comments = [];
const commentsQuerySnap = await commentsRef.get();
commentsQuerySnap.forEach((comment) => {
let commentData = comment.data();
comments.push(commentData);
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID);
comments.concat(childComments);
}
});
return comments;
} catch (error) {
functions.logger.log(error);
throw new functions.https.HttpsError('unknown', 'ERROR0', { message: error.message } )
}
}
不幸的是,当我尝试部署我的代码时,我在getChildComments
内部递归调用getChildComments
的行上得到了错误Parsing error. Unexpected token getChildComments
。从这一行中删除wait修复了构建问题,但递归调用没有完成。
我应该如何解决我的问题?或者有更好的方法来查询所有嵌套文档吗?
这是因为您在async
函数之外使用了await
(请注意,它在箭头函数内部!(。
const comments = [];
const commentsQuerySnap = await commentsRef.get();
commentsQuerySnap.forEach((comment) => {
let commentData = comment.data();
comments.push(commentData);
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID); // the keyword "await" here is invalid
comments = comments.concat(childComments);
}
});
但是,您不能只将async
添加到此箭头函数中,因为这样您的代码将无法正确地等待comments
数组的填充。
要正确修复此问题,除了使用Promise.all
等待检索每个注释(及其子注释(之外,还需要在commentsQuerySnap.docs
数组中使用.map()
。
const comments = [];
const commentsQuerySnap = await commentsRef.get();
await Promise.all(
commentsQuerySnap.docs.map(
async (comment) => {
let commentData = comment.data();
comments.push(commentData);
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID);
comments = comments.concat(childComments);
}
})
)
);
虽然上面的块可以工作,但注释数组可能与您预期的不一样。若必须维护获取的注释的顺序,以便它们与查询的顺序相同,那个么应该为每个文档返回构建的注释数组,然后在检索完所有注释后将其展开。
// removed const comments = []; here
const commentsQuerySnap = await commentsRef.get();
const arrayOfCommentThreads = await Promise.all(
commentsQuerySnap.docs.map(
async (comment) => {
let commentData = comment.data();
const commentThread = [commentData];
if (commentData.commentCount > 0) {
let childComments = await getChildComments(commentData.commentID);
commentThread = commentThread.concat(childComments);
}
return commentThread;
})
)
);
const comments = arrayOfCommentThreads.flat();
就我个人而言,我更喜欢使用排列运算符而不是像这样使用.concat
:
const commentsQuerySnap = await commentsRef.get();
const arrayOfCommentThreads = await Promise.all(
commentsQuerySnap.docs.map(
async (comment) => {
const commentData = comment.data();
if (commentData.commentCount === 0) {
return [commentData];
}
const childComments = await getChildComments(commentData.commentID);
return [commentData, ...childComments];
})
)
);
const comments = arrayOfCommentThreads.flat();