我想顺序使用firebase的onSnapshot函数。下面是我要应用的情况。
场景:
firestore中有2个收藏集。 Employees
和Projects
。在Employees
集合中,文档存储着员工的详细信息。它还存储该特定员工正在使用的Projects
文档的ID。在Projects
集合中,存储了项目的详细信息。
目标:
首先,我必须从Employees
集合中获取与特定员工有关的数据。然后,从获取的员工数据中,我将获得他/她正在从事的项目ID。因此,我需要从该ID中获取项目详细信息。因此,当任何与项目或员工相关的信息发生变化时,屏幕上的数据也应实时更改。
问题:
我试图编写一个嵌套代码。但是它仅对员工数据实时起作用。更新项目详细信息时,它不会更改。像这样...
admin.auth().onAuthStateChanged(async () => {
if (check_field(admin.auth().currentUser)) {
await db.collection('Employees').doc(admin.auth().currentUser.uid).onSnapshot(snap => {
...
let project_details = new Promise(resolve => {
let projects = [];
for (let i in snap.data().projects_list) {
db.collection('Projects').doc(snap.data().projects_list[i]).onSnapshot(prj_snap => {
let obj = prj_snap.data();
obj['doc_id'] = prj_snap.id;
projects.push(obj);
});
}
resolve(projects);
});
Promise.all([project_details]).then(items => {
...
// UI updation
});
...
});
}
});
正确的方法是什么?
答案 0 :(得分:2)
您实际上是在提出一个非常复杂的数据流方案。我会将其视为一个多步骤问题。您的目标实质上是:
所以我会解决类似的问题:
let uid;
let employeeUnsub;
let projectIds = [];
let projectUnsubs = {};
let projectData = {};
const employeesRef = firebase.firestore().collection('Employees');
const projectsRef = firebase.firestore().collection('Projects');
firebase.auth().onAuthStateChanged(user => {
// if there is already a listener but the user signs out or changes, unsubscribe
if (employeeUnsub && (!user || user.uid !== uid)) {
employeeUnsub();
}
if (user) {
uid = user.uid;
// subscribe to the employee data and trigger a listener update on changes
employeeUnsub = employeesRef.doc(uid).onSnapshot(snap => {
projectIds = snap.get('projects_list');
updateProjectListeners();
});
}
});
function updateProjectListeners() {
// get a list of existing projects being listened already
let existingListeners = Object.keys(projectUnsubs);
for (const pid of existingListeners) {
// unsubscribe and remove the listener/data if no longer in the list
if (!projectIds.includes(pid)) {
projectUnsubs[pid]();
delete projectUnsubs[pid];
delete projectData[pid];
render();
}
}
for (const pid of projectIds) {
// if we're already listening, nothing to do so skip ahead
if (projectUnsubs[pid]) { continue; }
// subscribe to project data and trigger a render on change
projectUnsubs[pid] = projectsRef.doc(pid).onSnapshot(snap => {
projectData[pid] = snap.data);
render();
});
}
}
function render() {
const out = "<ul>\n";
for (const pid of projectIds) {
if (!projectData[pid]) {
out += `<li class="loading">Loading...</li>\n`;
} else {
const project = projectData[pid];
out += `<li>${project.name}</li>`;
}
}
out += "</ul>\n";
}
上面的代码可以满足您的要求(在这种情况下,render()
函数仅返回一个字符串,但是您可以执行任何实际操作DOM /在此显示数据的操作)。
这是一个冗长的示例,但是您所谈论的是一个相当复杂的概念,即随着数据的变化而动态地动态结合实时数据。希望这能为您提供一些指导!