Paul
Paul

Reputation: 343

Firestore and flutter : Optimize data reads with streams

Explanation

I use BLoC logic to listen to my streams and I'd like to minimize data reads.

I understood that QuerySnapshot keeps track of previous documents and picks from cache if the document did not change.

The issue is that the snapshot doesn't contain information about the user's profile picture, name, etc. which i have to fetch using getInfoFromId(), and i would like to find a way not to use this function for every user when one user got changed, deleted or added

  Stream<List<FeedUser>> rolesToStream(String newsId) {
return Firestore.instance
    .collection('pages')
    .document(newsId).collection('users')
    .snapshots()
    .map(
        (snapshot){
      return snapshot.documents.map(
              (document){
            FeedUser user = FeedUser();
            user.fromSnapshot(document);
            user.contact = getInfoFromId(user.id);
            // The contact infos of a user is a future because we have to get it elsewhere, in a Firebase (NOT FIRESTORE) database. It theorically shouldn't be read after being read once after the event "RoleLoadMembers" 
            // Then we retrieve the contact infos after it is retrieved
            user.contact.then(
                    (contact){
                  user.retrievedContact = contact;
                }
            );
            return user;
          }
      ).toList();
    }
);
}

And here is how my BLoC listens to the data

  Stream<RoleState> _mapRolesToState() async* {
subscription?.cancel();
subscription =
    _feedRepository.rolesToStream(globalNews.feedId).listen((data) {
  add(RoleUpdated(data));
});
}

And here is how i change my roles

  void changeRole(String idFeed,String userId, AppRole role){
collectionReference
    .document(idFeed)
    .collection('users')
    .document(userId)
    .updateData({
  'role':EnumToString.parse(role),
});
}

My issue is the following : Anytime I am changing the role of a user, every other users get re-read by the stream and i have no clue how to fix it. Thanks in advance for the help.


States log

Possibles states:

Possible events :

Here is the log after loading for the first time :

I/flutter (27792): RoleLoadMembers
I/flutter (27792): Reading infos of the user : E4nT23Ohi0Za7JIQDaQ7Ohwe7Rn1
I/flutter (27792): Reading infos of the user : Svbj4tAIhIRcjQNqvYYsLSDXxwu2
I/flutter (27792): Reading infos of the user : cBm2KG6rEAbiaLGMAC08bvefNSn1
I/flutter (27792): RoleUpdated
I/flutter (27792): Transition { currentState: RoleMembersLoading, event: RoleUpdated, nextState: RoleLoadingSuccess }

And after changing role :

I/flutter (27792): ChangeRole
I/flutter (27792): Reading infos of the user : E4nT23Ohi0Za7JIQDaQ7Ohwe7Rn1
I/flutter (27792): Reading infos of the user : Svbj4tAIhIRcjQNqvYYsLSDXxwu2
I/flutter (27792): Reading infos of the user : cBm2KG6rEAbiaLGMAC08bvefNSn1
I/flutter (27792): RoleUpdated
I/flutter (27792): Transition { currentState: RoleLoadingSuccess, event: RoleUpdated, nextState: RoleLoadingSuccess }

After removing a member (Correctly deleted a member but still read info in the database):

I/flutter (27792): RemoveMember
I/flutter (27792): Reading infos of the user : E4nT23Ohi0Za7JIQDaQ7Ohwe7Rn1
I/flutter (27792): Reading infos of the user : Svbj4tAIhIRcjQNqvYYsLSDXxwu2
I/flutter (27792): RoleUpdated
I/flutter (27792): Transition { currentState: RoleLoadingSuccess, event: RoleUpdated, nextState: RoleLoadingSuccess }

Upvotes: 0

Views: 959

Answers (1)

Doug Stevenson
Doug Stevenson

Reputation: 317382

If you want to read from the client local cache first before querying the server, you can do that to avoid reads. Just specify a source option to query the cache first, then if it's not there, query the server. Read more about Firestore persistence.

Upvotes: 2

Related Questions