Search code examples
typescriptfirebaserxjsgoogle-cloud-firestoreangularfire

How to wait for multiple observable streams to resolve and return them together


In the observable pipeline below colWithIds$ gives me an observable of a firestore collection (a single array of objects) which I'll refer to as the parent documents. For each of those documents I use flatMap to make a single call for an associated document, which I'll call the child documents. I then store the parent and child docs on local variables:

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

The problems with this approach:

  1. There is a moment when the parent docs are available, but the child docs are not
  2. I would like to put this in a service for reuse, so assigning local variables in this way is problematic.

I'm looking for a way that I can wait until all values have been resolved and return a single object in the following form:

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

I'm open to other solutions to the problems listed above. Thanks in advance.


Solution

  • Is this what you are looking for? This way you don't query the database twice for 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}))
      ))
    );