在编写API时,我想收集对象的集合并提取它们的每个属性。一个属性是每个对象内的集合。但是,<QuerySnapshot>
似乎不支持异步迭代。
伪代码(使用TypeScript):
let objects = [];
const objectSnapshot = await admin.firestore().collection('object').get();
objectSnapshot.forEach(async (objectDoc) => {
let values = [];
const valueSnapshot = await admin.firestore().collection('object').doc(objectDoc.id).collection('value').get();
valueSnapshot.forEach((valueDoc) => {
values.push(valueDoc.data());
});
objects.push(values);
});
return objects;
以下代码不等待objects
的填充,并且不返回任何内容。
有什么建议吗?
答案 0 :(得分:2)
问题在于forEach本身不会同步运行,因此您需要在对象没有机会被填充之前返回它们。
您可以选择几种方法来解决此问题,在您的情况下,我建议您返回一个承诺数组,并等待它们完成后再返回。像这样:
const objectSnapshot = await admin.firestore().collection('object').get();
// Creates an array of promises that can be awaited later
// You can use the docs property which is an array, and then you can use map on it
const promises = objectSnapshot.docs.map(async (objectDoc) => {
// This will execute in parallel but will create a promise and add it to promises
const valueSnapshot = await admin.firestore().collection('object').doc(objectDoc.id).collection('value').get();
return valueSnapshot.docs.map((valueDoc) => valueDoc.data());
});
// Wait for all promises created before returning
return await Promise.all(promises);
答案 1 :(得分:1)
您在这里犯的错误是,您传递给forEach的回调不应标记为异步。当函数中所有其他等待的异步工作完成时,所有异步函数都会立即返回一个promise。这意味着forEach将迅速完成所有这些承诺,而无需等待它们解决。迭代完成后,每个回调中的异步工作将完成。这并不是您真正想要使用forEach的方式。
如果您想为每个文档快照执行一些异步工作,并收集所有异步工作的结果,则应该迭代objectSnapshot.docs
中的文档数组。然后,您可以对每个文档执行进一步的异步工作。作为JavaScript的惯用用法,使用数组的map()
函数将文档快照数组转换为promise数组。然后,您可以在该诺言数组上使用Promise.all()
,以等待所有工作完成。