How to get Firestore collection data with sub-collections in Angular

Google Firestore is a cloud-hosted NoSQL realtime database with a quite simple to use API. One problem I ran into a few times, is fetching sub-collections together with a collection. This use-case is not covered with the Firestore API and this article show a useful workaround.

There’s two ways to implement nested day. The first one is using type Array or Object with Object as the values. In this case the data is available in each document.

The second option of using sub-collections. Getting the sub-collection of a single document is simple:

db.collection('restaurants')
  .doc('arinell-pizza')
  .collection('ratings')
  .get()

Or when using ‘angularfire2/firestore’

this.firestoreService.col$('restaurants/arinell-pizza/ratings')

There’s no way of getting the sub-collections together with all the documents at once however. But a handy workaround is to map the stream of the collection documents, get it’s sub-collections and add them to the main collections documents.

this.firestoreService.colWithIds$('restaurants').pipe(
 switchMap((restaurants: any[]) => { 
   const res = restaurants.map((r: any) => { 
     return this.firestoreService
       .col$(`restaurants/${r.id}/ratings`)
       .pipe(
         map(ratings => Object.assign(restaurant, {ratings}))
       ); 
     }); 
   return combineLatest(...res); 
 })
).subscribe(restaurants => console.log(restaurants);

What’s happening here is, that the ‘restaurant’ values are mapped to it’s sub-collection observables. Those ‘ratings’ values however are mapped back to the ‘restaurant’ values, with the sub-collection ‘ratings’ data containing as a new property.

A tutorial for advanced usage of collections and the firestoreService class used in this tutorial can be found in https://angularfirebase.com/lessons/firestore-advanced-usage-angularfire/