Dart streams (Flutterfire): Should I use the where filter before or after mapping?

263

I got this answer from Aurimas Deimantas, after commenting on their article on medium.com. Below, I have adapted their answer to suit this question.


Firestore bills you based on how many document reads you have.

It will be better to filter before mapping, with

usersCollection.where('favorite food', isEqualTo: 'pasta')

because this will only read the documents where favorite food is pasta.

If you filter after mapping, like this:

users.where((user) => user.favorite_food == 'pasta');

then all user documents will be read, and after that, filtered. So Firestore will bill you for all the document reads instead of only those whose favorite food is pasta.

This is why it saves money to filter on the userscollection directly, before mapping it to your model.

If you want to map the stream to your model, you can do it after the where filter, by adding the .map(...) function after the .where(...) function, and this will map (& read) only the documents that pass the where filter, saving money.

Share:
263
Apps 247
Author by

Apps 247

Student Programmer

Updated on December 22, 2022

Comments

  • Apps 247
    Apps 247 over 1 year

    I'm making an app using Flutter, with Cloud Firestore for the backend. I have a stream which retrieves a list of user documents for all users and want to filter the users whose favorite food is "pasta". I don't want to load the other documents. Here is my stream, and the function which maps it to my user model.

    final CollectionReference usersCollection =
          FirebaseFirestore.instance.collection('Users');``
    
     List<MyAppUser> _userListFromSnapshot(QuerySnapshot snapshot) {
            return snapshot.docs.map((DocumentSnapshot doc) {
              return MyAppUser(
                uid: doc.id ?? '',
                name: (doc['name']).toString() ?? '',
                email: (doc['email']).toString() ?? '',
                favorite_food: (doc['favorite food']).toString() ?? '',
              );
            }).toList();
          }
        
      
    
    Stream<List<MyAppUser>> get users {
        return usersCollection.snapshots().map(_userListFromSnapshot);
      }
    

    Here is my user model if needed:

    class MyAppUser{
      final String uid;
      final String name;
      final String email;
      final String favorite_food;
    
      MyAppUser({
        this.name,
        this.email,
        this.uid,
        this.favorite_food,
      });
    }
    

    Should I use a where function after mapping or before?

    If I filter before mapping, I will have to do a where on the original stream like

    usersCollection.where('favorite food', isEqualTo: 'pasta')
    

    If I filter after mapping, I can get type safety:

    I listen to the stream with Provider: final users = Provider.of<List<MyAppUser>>(context); Then query like this:

    users.where((user) => user.favorite_food == 'pasta');
    

    I would prefer to use typesafety, but, will I be billed for reading only the filtered documents or all documents?

  • Apps 247
    Apps 247 almost 3 years
    But I want to make many filters, that's why I made a collection reference so I can reuse it. Also, is there a way to do it with type safety?
  • David Alberici
    David Alberici almost 2 years
    Did you find a way to add type safety to the filter?
  • Apps 247
    Apps 247 almost 2 years
    No, I haven't, sorry...