Home > Software design >  Subscribe to parent collection and child collection at once
Subscribe to parent collection and child collection at once

Time:06-11

Having a parent collection tables with documents which each one have a collection named orders. I want to subscribe to tables and listen to orders changes. What I tried:

At my tables service

watchTables(): Observable<any> {
    return this.afStore
      .collection('restaurants')
      .doc(this.rid)
      .collection('tables')
      .snapshotChanges()
      .pipe(
        map((data: any) =>
          data.map((documentDataTable: any) => ({
            id: documentDataTable.payload.doc.id,
            ...documentDataTable.payload.doc.data()
          }))
            .sort((a: any, b: any) => a.number - b.number)
        ),
        mergeMap((tables: any) => this.ordersService.watchOrders(tables))
      );
  }

At my orders service

watchOrders(tables: any): Observable<any> {
    let orders$: Observable<any>[] = [];

    tables.forEach((table: any) =>
      orders$.push(
        this.afStore
          .collection('restaurants')
          .doc(this.rid)
          .collection('tables')
          .doc(table.id)
          .collection('orders')
          .snapshotChanges()
          .pipe(
            map((data: any) => {
              return data.map((documentDataOrder: any) => ({
                id: documentDataOrder.payload.doc.id,
                ...documentDataOrder.payload.doc.data()
              }))
                .sort((a: any, b: any) => this.sortOrders(a, b))
            })
          ).pipe(
            map(data => ({ table: table, orders: data }))
          )
      ));

    return zip(orders$);
  }

Consuming tables service at my component

subscribeToTables() {
    this.tablesService
      .watchTables()
      .subscribe((collectedTablesData: any) => {
        console.log('table or orders changed');
      });
  }

I thougth about desestructuring data, but couldn't find an answer myself. Or I'm just messing with Observables, probably both.

Things I need in the solution:

  • I need orders data at the same time I get tables data(thats why in first place I thought orders would be part of table doc as an array of maps, but isn't that overkill?)
  • I need to know when orders change at my Table component because contains a rowexpansion datatable, table state in the datatable is dependant of orders state.

CodePudding user response:

As you seem to have gather already, there is no way to listen to parent documents and their child collections at once. Reads and listens in Firestore are shallow, and only cover one collection or all collections with a certain name.

You have a few options:

  1. You can include a field in the table document that indicates the state of its orders. At its simplest this could be a ordersLastUpdatedAt timestamp field, but you could also have a list of order IDs and the timestamp of their individual most recently updates. Either way, you should update the field(s) in the table document whenever a relevant order is updated too, and then use that as a trigger in your client to (re)load the orders for the table.

  2. You can also use a collection group query on orders at the path of the table document, as Sam showed in his answer to CollectionGroupQuery but limit search to subcollections under a particular document.

  • Related