TL; DR花费少量时间来获取少量文档
Scenerio:
我为每个帐户都有一个集合,每个帐户都包含一个projects
子集合和一个子集合tasks
。任务子集合中的每个文档可以进一步包含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个清单
我得出的结论是,由于任务的检索相当快,因此检索清单会使整个过程变慢。
所以我的问题如下:
谢谢。
问题是由于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] 删除。
我来说两句