gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 09:10:29 27 4
gpt4 key购买 nike

TL;DR 获取少量文档需要花费大量时间

Scenerio:
I have a collection for each account and each account contains a projects sub collection and tasks sub collection. Each document in the tasks sub collection can further contain checklists in the checkLists sub collection

注意:

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

插图:

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

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

代码:这样做的过程很慢,当我分析代码时,这个代码片段执行起来花费了很多时间。该代码段获取所有任务及其 list

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 个 list

我得出的结论是,检索 list 会减慢整个过程,因为检索任务的速度相当快。

所以我的问题如下:

  • 有什么方法可以优化上面的文档检索代码?
  • 有没有办法检索子文件通过重构数据和使用 collectionGroup 查询来更快地收集等等?

谢谢。

最佳答案

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

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

这会导致您的 for 循环在获取该特定任务的检查列表所需的时间内停止。

避免这种情况的方法是使用 Promise 链异步处理检查列表。当您循环执行任务时,您会为该任务的检查列表创建请求,为其结果添加一个监听器,然后发送它并立即转到下一个任务。

使用您的数据结构,检查列表与它们在服务器上的特定任务相关,但在您上面的代码中并没有绑定(bind)到它们。当使用相同的数据结构异步工作时,如果您只是使用带有 push() 的标准数组(例如,任务 B 的 list 获取可能在任务 A 之前完成,则它们将与您的任务无序).为了解决这个问题,在下面的代码中,我将 list 嵌套在 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 秒。

关于javascript - 如何在 Cloud Firestore 中高效地获取集合及其子集合的所有文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59477880/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com