Skip to content

AngularFirestore.firestore.enablePersistence makes snapshotChanges trigger twice #2808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
willemjanvankranenburg opened this issue Apr 23, 2021 · 9 comments

Comments

@willemjanvankranenburg
Copy link

Version info

Angular: 10.0.3

Firebase: 8.2.10

AngularFire: 6.1.4

@ionic/angular: 5.2.3

Ionic CLI: 6.12.1

Node: 12.18.4

How to reproduce these conditions

Steps to set up and reproduce

  • Create a new Ionic blank project
  • Add firebase and AngularFire packages with above mentioned versions
  • npm i
  • Add firebase config for any environment to the app.module.ts
  • Add following to the AppModule class:
constructor(private afs: AngularFirestore) {
      this.afs.firestore.enablePersistence();
}
  • add the following to the home.page.ts:
import { AngularFirestore } from '@angular/fire/firestore';
import { map } from 'rxjs/operators';
...
...
 constructor(private afs: AngularFirestore) {
    console.log('in constructor');
    this.afs
      .collection('<COLLECTION_NAME>')
      .doc('<DOCUMENT_ID>')
      .snapshotChanges()
      .pipe(
        map((a) => {
          console.log('in snapshotChanges()');
          const data = a.payload.data() as any;
          data.id = a.payload.id;
          return data;
        })
      )
      .subscribe((object: any) => {
        console.log(object);
      });
  }
  • run ionic serve -l from the terminal
  • After the localhost is started, open the javascript console, see "in snapshotChanges()" logged once.
  • Press F5, refresh the page
  • See "in snapshotChanges()" logged twice.

Sample data and security rules

Debug output

Two times the console.log('in snapshotChanges()');

Expected behavior

When calling .snapshotChanges() it should only resolve once initially and only a second time after the document is changed.

Actual behavior

.snapshotChanges() is called/triggerd twice. Once for the local cache, the second time because you're online. This was not the case in older versions (6.0.3) of angular fire.

@KingDarBoja
Copy link
Contributor

Please take a look at my comment at #2336 (comment)

@willemjanvankranenburg
Copy link
Author

willemjanvankranenburg commented Apr 26, 2021

Hi @KingDarBoja and @jamesdaniels

I didn't see the issue you linked, but thanks for the reply.

I still have some questions though.

Can you elaborate on why this is intended behaviour? I find it strange that the .snapshotChanges() is resolved twice. I don't really care where the data comes from, the SDK should handle the from cache/from online part in my opinion. I understand you sometimes want to know if the data is from cache or not, but I think it would make more sense if the code I wirte should check if it is from cache or not on places it matters, not the other way arround. 99% of the times I don't care where the data comes from and the 1 place I do care about it, I can set the source to 'server' or 'cache'.

I also see that you comented on the linked ticket on august 2020. In version 6.0.3 wich is released in September 2020, the behaviour was as I described. Was this a bug or feature that was not yet fixed/implemented?

@KingDarBoja
Copy link
Contributor

Not part of Firebase team but based on what I have observed and read (not 100% accurate), when you start listening to collection changes with snapshotChanges() or any other method, the first emission means that the document is being "added" to the cache and the second one is being "modified" from the server.

However, I have observed this behaviour even without setting enabledPersistence in my app, so gonna try to replicate it in a fresh project and share my findings.

@willemjanvankranenburg
Copy link
Author

Yeah, I kind of understand where that is comming from. But than I think it would always trigger twice. But the "strange" part is, when you get a document for the very first time (it was never retrieved on the device you are calling the subscribe) it only triggers once, because it is not in the cache yet.

Thanks for looking into it.

@jamesdaniels
Copy link
Member

There was a bug in older versions of 6.x where collections didn't always emit on source change. This may be why you didn't see "duplicate" emissions before. Ultimately with snapshotChanges() we want to give the developer maximum control over their Firestore usage, valueChanges() is what we suggest for the more simple cases.

@jamesdaniels
Copy link
Member

If valueChanges({ idField: 'id' }) was firing more than once I'd consider that a bug....

@IvanBean
Copy link

IvanBean commented May 3, 2021

valueChanges({ idField: 'id' }) was firing twice on add/update data due to metadata hasPendingWrites changes from true to false, as #2728 mentioned we might need distinctUntilChanged(... /* deep eq check */) on the return from valueChanges().

@jamesdaniels
Copy link
Member

hasPendingWrites would be expected. basically if any of the exposed fields change, i'd expect it to fire IMO

@IvanBean
Copy link

IvanBean commented Sep 1, 2021

Sorry but if I understand correctly, hasPendingWrites would be expected to trigger snapshotChanges() as a field of metadata, but shouldn't trigger valueChanges({ idField: 'id' }) since metadata would not be exposed this way. For the moment valueChanges() still emit twice while update data in AngularFire 7.0.2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants