[英]Get firestore documents from array of document references
目前,我正在对 Firestore 进行一组非常复杂的查询。
我正在尝试一次填充一个充满对其他文档的引用的数组,然后读取这些文档并将信息放入一个数组中。
更具体地说,对于这个示例,我在一个集合中有 4 个引用。 我想获取这些引用,然后使用这些引用,查询 4 个文档并用信息填充一个数组。
顺序如下:对tags
子集合中的所有文档进行查询,由下面的 function 处理:
getTagsOnPage(workspaceId: string, pageId: string) {
// get all of the references in the tags sub-collection, and puts them in an array
// get all id's, do not get data
return this.afs
.collection("users")
.doc(`${auth().currentUser.uid}`)
.collection<Workspace>("workspaces")
.doc(`${workspaceId}`)
.collection<Page>("pages")
.doc(`${pageId}`)
.collection("tags")
.snapshotChanges()
.pipe(
map((actions) => {
return actions.map((a) => {
const ref = a.payload.doc.get("reference");
return ref; // return an array of (id: reference) key-value pairs
});
})
);
}
这适用于执行订阅的以下代码:
this.pageService
.getTagsOnPage(this.workspaceId, this.currentPage.id)
.subscribe((data) => {
temp = data;
});
data
如下,通过控制台:
(3) ["/users/ucB5cF4Pj3PWhRn10c9mvqQbS7x2/workspaces/It1…1tSnPI5GJrniY82vZL/localTags/1p5Tscwn14PyK6zRaFHX", "/users/ucB5cF4Pj3PWhRn10c9mvqQbS7x2/workspaces/It1tSnPI5GJrniY82vZL/localTags/lFKoB0jngmtnALut2QS2", "/users/ucB5cF4Pj3PWhRn10c9mvqQbS7x2/workspaces/It1tSnPI5GJrniY82vZL/localTags/r6sf2SX6v87arU2rKsD5"]
现在,执行下一组数据读取是我开始困惑的地方。
我最初的方法是尝试一个 for 循环(对于这个数组的长度),但这将涉及迭代执行许多嵌套订阅,我认为这在这个意义上是不可能的。
我对 rxjs 相当陌生,并且只使用了 map 和 switchMap 运算符。 在这种情况下,我想我会使用诸如mergeMap
和/或flatMap,
但坦率地说,我不确定如何在这种情况下进行这项工作。 此外,处理我需要根据我得到的 documentReferences 数组获取文档的 for 循环也让我陷入了循环。
这是我目前的实现,到处都是; 我希望我正在尝试做的事情的感觉就在那里。 基本上,通过 getTagsOnPage 获取引用数组,等待 observable 结束,使用 switchMap 获取数据数组并循环遍历它; 理想情况下,订阅每个 ref 并添加到 tagData,然后返回:
let tagData;
this.pageService.getTagsOnPage(this.workspaceId, this.currentPage.id).pipe(
switchMap((data) => {
let references = data;
for (let j = 0; j < references.length; j++) {
let ref = this.afs.doc(`${references[j]}`);
ref.snapshotChanges().pipe(
map((actions) => {
const data = actions.payload.data();
tagData.push(data);
})
);
// push the data (different data var)
}
})
);
return tagData;
混乱,我知道,但我认为一旦我知道正确的运营商来使用它就会更有意义。
此外, atm this 返回一个空数组。 当我使用 switchMap 时出现以下错误:
Argument of type '(data: any[]) => void' is not assignable to parameter of type '(value: any[], index: number) => ObservableInput<any>'.
Type 'void' is not assignable to type 'ObservableInput<any>'.
感谢您的任何帮助!
使用switchMap
出错的原因是您没有返回 Observable。
当使用任何“ 高阶映射运算符”(switchMap、concatMap、mergeMap 等)时,提供的 function 必须返回一个 observable。 正如错误所述:“类型void
不可分配给类型ObservableInput<any>
”,您没有返回任何内容(void)。
下一件不太正确的事情是,在您的循环中,您引用ref.snapshotChanges().pipe()
,但您从未订阅它。 如您所知,可观察对象是惰性的,除非有订阅者,否则不会触发。
只要你在switchMap()
中返回一个 observable,它就会自动订阅它并发出它的值。
让我们换个角度想一想; 而不是循环第一次调用的结果,执行它们,然后将值推送到数组中。 我们可以取而代之,将结果转换为可观察的 stream,它会发出它们各自调用的所有结果,并将它们组合成一个数组供您使用。 但是......有一个细微的区别:我建议不要在 stream 之外有一个单独的tagData
数组,而是让你的 observable 返回你需要的tagData
表单作为Observable<TagData[]>
。
我认为这样的事情对你有用:
tagData$ = this.pageService.getTagsOnPage(this.workspaceId, this.currentPage.id).pipe(
switchMap(references => from(references)),
mergeMap(ref => this.afs.doc(ref).snapshotChanges()),
map(actions => actions.payload.data()),
scan((allTagData, tagData) => [...allTagData, tagData], [])
})
);
让我们打破它!
现在,您可以简单地执行以下操作: tagData$.subscribe()
并对生成的数据数组执行您想要的操作。 或者你甚至可以在你的模板中使用异步 pipe而不是在你的组件中订阅。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.