如何在Cloud Firestore中高效地获取集合及其子集合的所有文档

阿达什

TL; DR花费少量时间来获取少量文档

Scenerio:
我为每个帐户都有一个集合,每个帐户都包含一个projects子集合和一个子集合tasks任务子集合中的每个文档可以进一步包含checkLists子集合中的清单

注意:

  • 项目可以包含任务,而任务又可以包含清单。
  • 可以独立创建任务,即;它不一定总是项目的一部分。
  • 项目和任务都是顶级子集合,而checkLists子集合嵌套在每个任务中。

插图:

someTopLevelDB
   |
   |____ accountId1
   |         |______projects
   |         |         |_______ projectId1
   |         |
   |         |______tasks
   |                  |________taskId1 (belongs to projectId1)
   |                  |           |
   |                  |           |________checkLists
   |                  |                         |
   |                  |                         |_____checkListId1
   |                  |
   |                  |________taskId2 (standalone)

用例:当用户单击重复的项目(从UI)时,我必须创建整个项目的副本,即;所有任务,清单等。

代码:这样做的过程很慢,当我分析代码时,此代码段花了很多时间来执行。该代码段提取所有任务及其清单

let db = admin.firestore();

function getTasks(accountId) {
    return db.collection('someTopLevelDB')
        .doc(accountId)
        .collection('tasks')
        .where('deleted', '==', false)
        .get();
}


function getCheckLists(accountId, taskId) {
    return db.collection('someTopLevelDB')
        .doc(accountId)
        .collection('tasks')
        .doc(taskId)
        .collection('checkLists')
        .where('deleted', '==', false)
        .get();
}


async function getTasksAndCheckLists(accountId) {
    try {
        let records = { tasks: [], checkLists: [] };

        // prepare tasks details
        const tasks = await getTasks(accountId);
        const tasksQueryDocumentSnapshot = tasks.docs;
        for (let taskDocumentSnapshot of tasksQueryDocumentSnapshot) {
            const taskId = taskDocumentSnapshot.id;
            const taskData = taskDocumentSnapshot.data();
            const taskDetails = {
                id: taskId,
                ...taskData
            };
            records.tasks.push(taskDetails);

            // prepare check list details
            checkListQueryDocumentSnapshot = (await getCheckLists(accountId, taskId)).docs;
            for (let checkListDocumentSnapshot of checkListQueryDocumentSnapshot) {
                const checkListId = checkListDocumentSnapshot.id;
                const checkListData = checkListDocumentSnapshot.data();
                const checkListDetails = {
                    id: checkListId,
                    ...checkListData
                };
                records.checkLists.push(checkListDetails);
            }
        }
        console.log(`successfully fetched ${records.tasks.length} tasks and ${records.checkLists.length} checklists`);
        return records;
    } catch (error) {
        console.log('Error fetching docs ====>', error);
    }
}




// Call the function to fetch records
getTasksAndCheckLists('someAccountId')
    .then(result => {
        console.log(result);
        return true;
    })
    .catch(error => {
        console.error('Error fetching docs ===>', error);
        return false;
    });

执行状态:
在220.532秒内成功获取627个任务和51个清单

我得出的结论是,由于任务的检索相当快,因此检索清单会使整个过程变慢

所以我的问题如下:

  • 有什么方法可以优化上述代码中的文档检索?
  • 有什么方法可以通过重塑数据并使用collectionGroup查询等来更快地检索子集合的文档?

谢谢。

samthecodingman

问题是由于await在此处使用for循环内部引起的

checkListQueryDocumentSnapshot = (await getCheckLists(accountId, taskId)).docs;

这会导致for循环停顿一段时间,直到获取该特定任务的检查列表为止。

避免这种情况的方法是使用Promise链异步处理检查表。遍历任务时,将为该任务的检查表创建请求,向其结果添加侦听器,然后将其发送并立即移至下一个任务。

对于您的数据结构,检查表与服务器上的特定任务相关,但是在上面的代码中它们与它们无关。当使用相同的数据结构异步工作时,这意味着如果您仅使用标准数组push()(例如,任务B的清单提取可能在任务A之前完成),它们将与您的任务不协调。为了解决这个问题,在下面的代码中,我将清单嵌套在taskDetails对象下,因此它们仍被链接。

async function getTasksAndCheckLists(accountId) {
    try {
        let taskDetailsArray = [];

        // fetch task details
        const tasks = await getTasks(accountId);

        // init Promise holder
        const getCheckListsPromises = [];

        tasks.forEach((taskDocumentSnapshot) => {
            const taskId = taskDocumentSnapshot.id;
            const taskData = taskDocumentSnapshot.data();
            const taskDetails = {
                id: taskId,
                checkLists: [], // for storing this task's checklists
                ...taskData
            };
            taskDetailsArray.push(taskDetails);

            // asynchronously get check lists for this task
            let getCheckListPromise = getCheckLists(accountId, taskId)
                .then((checkListQuerySnapshot) => {
                    checkListQuerySnapshot.forEach((checkListDocumentSnapshot) => {
                        const checkListId = checkListDocumentSnapshot.id;
                        const checkListData = checkListDocumentSnapshot.data();
                        const checkListDetails = {
                            id: checkListId,
                            ...checkListData
                        };

                        taskDetails.checkLists.push(checkListDetails);
                    });
                });

            // add this task to the promise holder
            getCheckListsPromises.push(getCheckListPromise);
        });

        // wait for all check list fetches - this is an all-or-nothing operation
        await Promise.all(getCheckListsPromises);

        // calculate the checklist count for all tasks
        let checkListsCount = taskDetailsArray.reduce((acc, v) => acc+v.checkLists.length, 0);

        console.log(`successfully fetched ${taskDetailsArray.length} tasks and ${checkListsCount} checklists`);
        return taskDetailsArray;
    } catch (error) {
        console.log('Error fetching docs ====>', error);
    }
}

通过这些更改,您应该看到函数运行的时间大大减少了。根据您提供的时间,我估计它将下降到大约2-3秒。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何从Firestore中的文档ID数组中获取所有子集合文档

来自分类Dev

是否可以在Cloud Firestore上查询Field并获取主集合字段以及具有子集合文档的子集合?

来自分类Dev

如何在Firestore / Flutter中获取子集合和文档

来自分类Dev

Firestore 规则:如何根据包含子集合的文档字段允许访问子集合?

来自分类Dev

如何在Cloud Firestore中有效地获取不同集合中具有特定ID的文档?

来自分类Dev

Firestore集合组查询-如何订购子集合所属的父文档?

来自分类Dev

如何在React-native中从Firestore中读取子集合的文档字段

来自分类Dev

Firestore获取子集合的所有文档

来自分类Dev

从 Firebase 的 Cloud Firestore 中删除文档会删除该文档中的任何子集合吗?

来自分类Dev

如何使用Flutter获取Firestore中每个集合的子集合

来自分类Dev

如何在 Firestore 中获取子集合引用 [Node JS]

来自分类Dev

Mongodb:如何获取子集合列表

来自分类Dev

Hibernate-如何获取子集合?

来自分类Dev

Firestore:更新父级后如何将文档添加到子集合

来自分类Dev

在React中如何从子集合中的文档中获取和显示数据

来自分类Dev

如何从文档中检索未知子集合

来自分类Dev

如何使用子集合创建文档

来自分类Dev

如何按子集合中的项目执行搜索文档

来自分类Dev

Firestore安全规则-如何保护子集合?

来自分类Dev

如何访问 angular 和 firestore 中的子集合

来自分类Dev

Firestore:如何使用 documentID 读取子集合数据?

来自分类Dev

如何将python列表的所有子集合并到n个容器中

来自分类Dev

如何将python列表的所有子集合并到n个容器中

来自分类Dev

获取Firestore中子集合内所有文档的特定值的列表

来自分类Dev

如何将数据添加到 Firestore 数据库子集合中的特定文档?

来自分类Dev

如何从 Firestore 的集合中获取 String 数组中的所有文档(包括数据)?

来自分类Dev

是否可以从父集合(firebase cloud firestore)访问子集合?

来自分类Dev

删除的集合中的文档和子集合会如何处理?

来自分类常见问题

如何使用Cloud Firestore获取集合中文档的数量

Related 相关文章

  1. 1

    如何从Firestore中的文档ID数组中获取所有子集合文档

  2. 2

    是否可以在Cloud Firestore上查询Field并获取主集合字段以及具有子集合文档的子集合?

  3. 3

    如何在Firestore / Flutter中获取子集合和文档

  4. 4

    Firestore 规则:如何根据包含子集合的文档字段允许访问子集合?

  5. 5

    如何在Cloud Firestore中有效地获取不同集合中具有特定ID的文档?

  6. 6

    Firestore集合组查询-如何订购子集合所属的父文档?

  7. 7

    如何在React-native中从Firestore中读取子集合的文档字段

  8. 8

    Firestore获取子集合的所有文档

  9. 9

    从 Firebase 的 Cloud Firestore 中删除文档会删除该文档中的任何子集合吗?

  10. 10

    如何使用Flutter获取Firestore中每个集合的子集合

  11. 11

    如何在 Firestore 中获取子集合引用 [Node JS]

  12. 12

    Mongodb:如何获取子集合列表

  13. 13

    Hibernate-如何获取子集合?

  14. 14

    Firestore:更新父级后如何将文档添加到子集合

  15. 15

    在React中如何从子集合中的文档中获取和显示数据

  16. 16

    如何从文档中检索未知子集合

  17. 17

    如何使用子集合创建文档

  18. 18

    如何按子集合中的项目执行搜索文档

  19. 19

    Firestore安全规则-如何保护子集合?

  20. 20

    如何访问 angular 和 firestore 中的子集合

  21. 21

    Firestore:如何使用 documentID 读取子集合数据?

  22. 22

    如何将python列表的所有子集合并到n个容器中

  23. 23

    如何将python列表的所有子集合并到n个容器中

  24. 24

    获取Firestore中子集合内所有文档的特定值的列表

  25. 25

    如何将数据添加到 Firestore 数据库子集合中的特定文档?

  26. 26

    如何从 Firestore 的集合中获取 String 数组中的所有文档(包括数据)?

  27. 27

    是否可以从父集合(firebase cloud firestore)访问子集合?

  28. 28

    删除的集合中的文档和子集合会如何处理?

  29. 29

    如何使用Cloud Firestore获取集合中文档的数量

热门标签

归档