Search code examples
angularfirebasegoogle-cloud-firestoreprimeng

How do I optimise joining multiple Firebase Firestore collection document values together in Angular?


I am looking for a more optimal way to implement the following method getting all my documents from my permits collection, than mapping company and process area data into my permit data used in a PrimeNG table.

Performance > Firebase document reads usage.

Here is my getAllPermits$() method so far:

getAllPermits$() {
    return combineLatest([
      collectionData(this.permitCollection) as Observable<any[]>, //will query this later to only show active permits
      collectionData(this.companyCollection, {idField: 'uid'}) as Observable<Company[]>,
      collectionData(this.processAreasCollection, {idField: 'uid'}) as Observable<ProcessArea[]>,
    ]).pipe(
      map(([permits, companies, processAreas]) => {
        return permits.map(permit => {
          if (permit.companyUid) {
            const company = companies.find(c => c.uid === permit.companyUid);
            if (company) {
              permit = {...permit, companyName: company?.name ?? 'Error'};
            } else {
              permit = {...permit, companyName: 'Not Found'};
            }
          } else {
            permit = {...permit, companyName: 'No Company'};
          }

          if (permit.processArea) {
            const processArea = processAreas.find(pa => pa.assetNumber === permit.processArea);
            if (processArea) {
              permit = {...permit, processAreaName: processArea?.description ?? 'Error'};
            } else {
              permit = {...permit, processAreaName: 'Not Found'};
            }
          } else {
            permit = {...permit, processAreaName: 'No Process Area'};
          }
          return permit;
        });
      })
    );
  }

Is querying single documents in the companyCollection and processAreasCollection more efficient, as opposed to mapping as shown above?

Context: I would normally have 200 - 500 active permits (this isn't in the code yet, but this is easy implement later).

  • companyCollection = 300+ companies where we might use 100-150 companies in the currently active permits.
  • processAreas = 160+ areas - again, we might use 50-70 areas in the actively shown permits.

I am using a big portion of the company and process area collection data, hence the question.


Solution

  • For the best performance, move away from the relational model that you currently have, and embrace the NoSQL nature of Firestore by duplicating data.

    For example, if you duplicate the data that you need from processAreasCollection and companyCollection into each document in permitCollection, you only need to load the documents from the latter. This may seem very unnatural at first, but it's actually key to getting great performance out of a NoSQL database like Firestore.

    If this is new to you, I recommend reading NoSQL data modeling and watching the Get to know Cloud Firestore video series.