Search code examples
fluttercachinggoogle-cloud-firestoreservercloud

How can I reduce my reads on Firestore with Flutter?


I know that there is a possibility to minimize unnecessary reads with the command GetOptions (source: Source.cache). My question would be, how can I run my Firestore query with get first via the cache and if there is nothing there, i.e. the cache is empty, via the server?

My code will be something like...

  _getLikes() {
User _user = _firebaseAuth.currentUser;
 FirebaseFirestore.instance.collection('Users')
    .doc(_user.uid)
    .collection("Likes")
    .where('liked', isEqualTo: true)
    .snapshots()
    .listen((_querySnapshot) {
  //likedList.clear();
  if (_querySnapshot.docs.isNotEmpty) {
    _querySnapshot.docs.forEach((_likedDocumentSnapshot) async {
      await  FirebaseFirestore.instance.collection('Users')
          .doc(_likedDocumentSnapshot.data()['likedId'])
          .get()
          .then((_usersDocumentSnapshot) {
        if (_usersDocumentSnapshot.exists) {
          User _tempUser =
              User.fromDocument(_usersDocumentSnapshot);

          liked.add(_tempUser);

          if (mounted) setState(() {});
        }
      });
    });
  }
});
}

User is my class in which I regulate server things such as the name and age of the user.

I just need to know how can I use this

GetOptions(source: Source.cache)

inside the

get()

and if the cache is empty

GetOptions(source: Source.server)

First my function getLikes() should look if the data is inside the cache and load it from there. If it is not inside the cache, than it should load the data from server.

I'm very grateful for any help, couldn't find anything on Google.


Solution

  • There are 2 approaches for you to achieve this :

    1. One with source options. With the source options, get() calls on DocumentReference and Query. By providing the source value, these methods can be configured to fetch results only from the server, only from the local cache, or attempt to fetch results from the server and fall back to the cache (which is the default).

    This is a code example to show how you would use the source options to know if the data was fetched from cache, server or default. You can also write code to query the cache first, then fall back to the server if not present like below :

    let snapshot = await documentRef.get({ source: 'cache' }
    if (!snapshot.exists) {
       snapshot = await documentRef.get({ source: 'server' })
    }
    

    This could be a good way of saving on the cost of read operations, but if source : cache is true everytime, the app does not read the document from the server, but only from cache, it might never see future changes to the document’s data. For that reason, the second option - SnapshotMetadata is more suitable.

    1. Second, use the fromCache property in the SnapshotMetadata in your snapshot event. If fromCache is true, the data came from the cache and might be devoid of changes/updates.If fromCache is false, the data is complete and current with the latest updates on the server.

    This is a code example to show how you would use the SnapshotMetadata changes to know if the data was fetched from cache or server.