【问题标题】:How to wait for multiple observable streams to resolve and return them together如何等待多个可观察流解决并一起返回它们
【发布时间】:2020-01-07 22:02:40
【问题描述】:

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
}

我对上述问题的其他解决方案持开放态度。提前致谢。

【问题讨论】:

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


    【解决方案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】:

      如果我正确理解您的操作,您可以使用 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};
               })
             )
          }),
        )
      

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

      【讨论】:

      • 我尝试了 forkJoin,但我的 observable 从未完成。 SwitchMap 也只返回了一个孩子,取消了其他孩子。此外,我认为可观察模式中的可观察是反模式。我发布了我的解决方案作为答案。
      【解决方案3】:
      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$);
      }
      

      【讨论】:

        猜你喜欢
        • 2012-05-04
        • 2012-07-27
        • 2019-10-05
        • 1970-01-01
        • 2017-09-08
        • 1970-01-01
        • 2022-08-19
        • 1970-01-01
        • 2015-05-30
        相关资源
        最近更新 更多