Firebase函数:有没有一种方法可以异步地迭代多个集合?

时间:2019-02-08 23:57:20

标签: typescript firebase google-cloud-firestore google-cloud-functions

在编写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的填充,并且不返回任何内容。

有什么建议吗?

2 个答案:

答案 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(),以等待所有工作完成。