如何等待多个可观察流解析并将它们 return 在一起
How to wait for multiple observable streams to resolve and return them together
在下面的可观察管道中,colWithIds$
为我提供了一个 firestore 集合(单个对象数组)的可观察对象,我将其称为父文档。对于这些文档中的每一个,我都使用 flatMap
对关联文档进行一次调用,我将其称为子文档。然后我将父文档和子文档存储在局部变量中:
this.db.colWithIds$('parentCollection')
.pipe(
tap(parentDocs => this.parentDocs = _.keyBy(parentDocs, '_id')),
flatMap(parentDocs => combineLatest(parentDocs.map(doc => this.db.doc(`childCollection/${doc.childId}`).get()))),
map(snaps => convertSnaps(snaps)),
tap(childDocs => this.childDocs = _.keyBy(childDocs, '_id'))
).subscribe()
这种方法的问题:
- 有时父文档可用,但子文档不可用
- 我想把它放在一个服务中重用,所以这样分配局部变量是有问题的。
我正在寻找一种方法,可以等到所有值都已解析并且 return 具有以下形式的单个对象:
{
parentDocs: [{}, {}, ...], // the documents
childDocs: [{}, {}, ...], // the documents
}
我对上述问题的其他解决方案持开放态度。提前致谢。
如果我理解你正在尝试做什么,你可以使用 forkJoin
这是一个运算符,它接收一个 Observables 数组作为输入,并在一个数组中的所有 Observables 都发出时发出。
在这种情况下,您的代码可能类似于以下几行
this.db.colWithIds$('parentCollection')
.pipe(
// here you use concatMap or switchMap, depending on your logic, to pass
// the control to the next Observable build using forkJoin
concatMap(parentDocs => {
// with this Array map function you create an array of Observables
const childDocObs = parentDocs.map(doc => this.db.doc(`childCollection/${doc.childId}`).get());
// here, via forkJoin, you return a single Observable which emits when
// all the Observables of the childDocObs array have emitted, and what
// is emitted is an array containing the data emitted by the sing Observables
// passed in as input
return forkJoin(childDocObs).pipe(
// with this map we make sure we return both parentDocs and childDocs
// without having to use local variables
map(snaps => {
const childDocs = convertSnaps(snaps);
return {parentDocs, childDocs};
})
)
}),
)
因此,这段代码应该 returns 一个 Observable,当所有 Observable 都被解析时,它会发出 parentDocs
和 childDocs
。
getJoinedData(parentId: string): Observable<[ ParentType, ChildType ]> {
const parent$ = this.db.colWithIds$(`parentCollection`)
.pipe(map(parentDocs => _.keyBy(parentDocs, '_id')));
const children$ = parent$.pipe(
flatMap(parentDocs => combineLatest(_.map(parentDocs, parent => this.db.docWithId$(`childDocs/${parent.childId}`)))),
map(children => _.keyBy(children, '_id')));
return combineLatest(parent$, children$);
}
这是您要找的吗?这样你就不会为 parents.
查询数据库两次
this.db.colWithIds$(`parentCollection`).pipe(
map(parentDocs => _.keyBy(parentDocs, '_id')),
flatMap(parentDocs => combineLatest(_.map(parentDocs, parent => this.db.docWithId$(`childDocs/${parent.childId}`))).pipe(
map(childDocs => _.keyBy(childDocs, '_id')),
map(childDocs => ({parentDocs, childDocs}))
))
);
在下面的可观察管道中,colWithIds$
为我提供了一个 firestore 集合(单个对象数组)的可观察对象,我将其称为父文档。对于这些文档中的每一个,我都使用 flatMap
对关联文档进行一次调用,我将其称为子文档。然后我将父文档和子文档存储在局部变量中:
this.db.colWithIds$('parentCollection')
.pipe(
tap(parentDocs => this.parentDocs = _.keyBy(parentDocs, '_id')),
flatMap(parentDocs => combineLatest(parentDocs.map(doc => this.db.doc(`childCollection/${doc.childId}`).get()))),
map(snaps => convertSnaps(snaps)),
tap(childDocs => this.childDocs = _.keyBy(childDocs, '_id'))
).subscribe()
这种方法的问题:
- 有时父文档可用,但子文档不可用
- 我想把它放在一个服务中重用,所以这样分配局部变量是有问题的。
我正在寻找一种方法,可以等到所有值都已解析并且 return 具有以下形式的单个对象:
{
parentDocs: [{}, {}, ...], // the documents
childDocs: [{}, {}, ...], // the documents
}
我对上述问题的其他解决方案持开放态度。提前致谢。
如果我理解你正在尝试做什么,你可以使用 forkJoin
这是一个运算符,它接收一个 Observables 数组作为输入,并在一个数组中的所有 Observables 都发出时发出。
在这种情况下,您的代码可能类似于以下几行
this.db.colWithIds$('parentCollection')
.pipe(
// here you use concatMap or switchMap, depending on your logic, to pass
// the control to the next Observable build using forkJoin
concatMap(parentDocs => {
// with this Array map function you create an array of Observables
const childDocObs = parentDocs.map(doc => this.db.doc(`childCollection/${doc.childId}`).get());
// here, via forkJoin, you return a single Observable which emits when
// all the Observables of the childDocObs array have emitted, and what
// is emitted is an array containing the data emitted by the sing Observables
// passed in as input
return forkJoin(childDocObs).pipe(
// with this map we make sure we return both parentDocs and childDocs
// without having to use local variables
map(snaps => {
const childDocs = convertSnaps(snaps);
return {parentDocs, childDocs};
})
)
}),
)
因此,这段代码应该 returns 一个 Observable,当所有 Observable 都被解析时,它会发出 parentDocs
和 childDocs
。
getJoinedData(parentId: string): Observable<[ ParentType, ChildType ]> {
const parent$ = this.db.colWithIds$(`parentCollection`)
.pipe(map(parentDocs => _.keyBy(parentDocs, '_id')));
const children$ = parent$.pipe(
flatMap(parentDocs => combineLatest(_.map(parentDocs, parent => this.db.docWithId$(`childDocs/${parent.childId}`)))),
map(children => _.keyBy(children, '_id')));
return combineLatest(parent$, children$);
}
这是您要找的吗?这样你就不会为 parents.
查询数据库两次this.db.colWithIds$(`parentCollection`).pipe(
map(parentDocs => _.keyBy(parentDocs, '_id')),
flatMap(parentDocs => combineLatest(_.map(parentDocs, parent => this.db.docWithId$(`childDocs/${parent.childId}`))).pipe(
map(childDocs => _.keyBy(childDocs, '_id')),
map(childDocs => ({parentDocs, childDocs}))
))
);