如何等待多个可观察流解析并一起返回

时间:2019-09-05 03:30:38

标签: typescript firebase rxjs google-cloud-firestore angularfire

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()

这种方法的问题:

  1. 有一段时间,父文档可用,但子文档不可用
  2. 我想将其放在服务中以供重用,因此以这种方式分配局部变量是有问题的。

我正在寻找一种方法,可以等到所有值都已解析并以以下形式返回单个对象:

{
  parentDocs: [{}, {}, ...], // the documents
  childDocs: [{}, {}, ...], // the documents
}

我愿意接受其他解决上述问题的方法。预先感谢。

3 个答案:

答案 0 :(得分:1)

如果我正确理解了您要做什么,则可以使用forkJoin,它是一个运算符,它接收Observable数组作为输入,并在数组中的所有Observable都发出时发出。

在这种情况下,您的代码可能类似于以下几行

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};
         })
       )
    }),
  )

因此,此代码应返回一个Observable,当所有Observable都解决后,该Observable会发出parentDocschildDocs

答案 1 :(得分:1)

这是您要找的东西吗?这样,您就不会两次查询数据库的父母。

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}))
  ))
);

答案 2 :(得分:0)

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$);
}