In this quick snippet I will show you how to combine two or more Firestore collections from AngularFire into a single realtime Observable.
The Problem
Let’s imagine you have queried multiple Firestore collections, but want combine them and iterate over them using ngFor
- this is a common requirement when dealing with subcollections. In addition, you want to maintain a realtime listener to update the data if a new object is added to either query.
Your collections might look something like this
const usersRef = this.afs.collection('users');
const fooPosts = usersRef.doc('userFoo').collection('posts').valueChanges();
const barPosts = usersRef.doc('userBar').collection('posts').valueChanges();
We want a fooPosts + barPosts
as a single Observable array.
Solution
We can accomplish our goal of a single unified collection with RxJS and plain JS array reduce mapping. This example will not keep maintain a specific ordering between the arrays, but you can add your own client-side logic control the ordering of the result array.
The magic RxJS operator here is combineLatest, which listens for updates on either individual Observable, but emits the both results together each time.
We can then use the plain JS reduce and concat methods to flatten the two arrays.
import { combineLatest } from 'rxjs/observable/combineLatest';
const combinedList = combineLatest<any[]>(fooPosts, barPosts).pipe(
map(arr => arr.reduce((acc, cur) => acc.concat(cur) ) ),
)
Now you can loop over the results in the HTML.
<div *ngFor="let post of combinedPosts | async">
{{ post | json }}
</div>
Questions?
Ask questions via GitHub below OR chat on Slack #questions