angularfirebasegoogle-cloud-firestoreangular-akita

SyncCollection in Akita Collection Service too expensive?


I have a query around the CollectionService() method available in akita-ng-fire module. I have created a service that extends CollectionService() and uses syncCollection to maintain a sync between a firestore document and my web client. This is how the service definition looks:

@Injectable({providedIn: 'root'})
@CollectionConfig({path: 'someDoc/:customId/anotherDoc'})
export class MyService extends CollectionService<WorkspaceState> {

    constructor(store: WorkspaceStore) {
        super(store);
        this.store.setHasCache(true, {restartTTL: true});
    }

    // service methods ......
}

I use it in the onInit directive in my component to initialise a sync.

    ngOnInit() {
        this.sub = this.myService.syncCollection().pipe(
            concatMap(_ => this.query.myDoc$.pipe(
                tap(d => this.myService.markActive(d.customId)),
                tap(d => this.customId = d.customId),
            )),
            tap(d => this.router.navigate(['somePlace', d. customId])),
        ).subscribe();
    }

However, I see this sync goes through ~5 reads every minute. Is there a way to reduce this ? I feel this is expensive for me cause we have this service as a core service that is used to maintain sync with a business critical document.

Any suggestions from the community would be helpful


Solution

  • syncCollection listens on every change of every document on your collection. This is great to begin, but once your application grows you want to be more precise.

    1. Only sync when you need to: Use syncCollection for pages with a list and syncDoc for pages with a single view. And don't forget to unsubscribe when you leave the pages (I like to use Guards for that purpose).
    2. If you don't need to be always up-to-date, consider using snapshot instead with getValue. There are some cases when you don't want to perform read in realtime like none-collaborative forms, or lists that just display one key that are not supposed to change. In this case you can use getValue() for a collection or getValue(id) for a document.
    3. Use queryFn to listen on fewer documents. Most of the time you don't want to get the whole collection but only a subset of it: syncCollection(ref => ref.limitTo(10).where(...).
    4. Don't worry too much about price. You'll pay some €/millions reads. The time you spend trying to optimize it willl cost way more to your company than firebase's reads cost. Keep price in your head when you code, but don't spend too much time optimizing things ;).

    As a side note I don't think the setHasCache will have any effect here. Firebase uses IndexedDB to cache the data you already used. So if nothing changed since last time you don't pay for it.