4

I use AngularFire (6.1.4) in my Angular (11.1.1) project with offline persistence and I was surprised to see that on load, the data is provided twice: once from the cache and once from the server (I use the variable fromCache to proof the source).

app.module.ts

import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';

@NgModule({
  imports: [
    AngularFireModule.initializeApp(Config),
    AngularFirestoreModule.enablePersistence(),
    AngularFireAuthModule
  ]
})
export class AppModule { ...}

DB Service

this.firestoreRef.collection(collectionName, query)
    .snapshotChanges()
    .pipe(
      map(actions => actions.map(a => {
         console.log('fromCache -> ', a.payload.doc.metadata.fromCache);
       }))
    ).subscribe(/* Just for TEST purposes */);

I was thinking the same logic for the get() options would apply:

Setting to default (or not setting at all), causes Firestore to try to retrieve an up-to-date (server-retrieved) snapshot, but fall back to returning cached data if the server can't be reached.

Why also the cached data is returned if the user is online?

Of course I can listen offline/online events (though they are not reliable) or even a SW to check if the client is online or not, and use or skip the cached results accordingly, but shouldn't Firestore detect online/offline state?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Francesco
  • 9,947
  • 7
  • 67
  • 110
  • 1
    The user who gave a negative vote could at least explain WHY did so. At leat me and other people can improve questions or further refine them. I could not find an answer to my question in the docs. Voting just according to "feeling" is a sad habit – Francesco Feb 09 '21 at 14:32

1 Answers1

2

From the documentation on listening to realtime updates:

You can listen to a document with the onSnapshot() method. An initial call using the callback you provide creates a document snapshot immediately with the current contents of the single document.

While this talks about a single document, the same applies when listening to multiple documents.

So what you're seeing is just how Firestore works: when you attach a listener for the snapshot, it immediately fires with the local state of the data (if any). Then it checks against the server, which may take some time, and fires again with the state from the server, if that is different from the local cache (or you've requested to get called with metadata changes too).

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks Frank for the great answer (I read that doc page and blindly miss the very first 3 lines). Some custom logic then is needed to filter this "double" set of data (I tipically use `valueChanges` instead of `onSnapshot `) since the 2. time is fired with the data from the server even if it is the first page load, hence the data should be the same as in the cache/local. Is there a sort of best practice to avoid having to load the data twice in the HTML templates in these cases? – Francesco Feb 09 '21 at 15:17
  • 1
    The best practice is to display the data as it comes in. So the first time you show the local data, and then when the data from the server is available you update the UI with that – Frank van Puffelen Feb 09 '21 at 15:29
  • Thanks again. I will have to see how this fits with ngrx actions as they will be triggered twice (eg. LoadDataSuccess), but it can still make sense as it reflects the changes that come from the server. – Francesco Feb 09 '21 at 15:32