Search code examples
flutterfirebasegoogle-cloud-firestorestream-builder

Flutter Firebase - how to make a more customizable query in my StreamBuilder


I am developing a kids reading app in Flutter. I am using Firebase Firestore and I have a collection of USERS and BOOKS. Each book has a reading level 1,2,3 or 4 and their respective level is stored in a Field. When the user is at the homepage, all books are displayed using a StreamBuilder. I want to add the functionality that the user can toggle ON or OFF specific reading levels, so only books are shown that are age appropriate. For this I have created 4 buttons for each reading level that can each be toggled ON or OFF.

I used different approaches at storing the preference of the user:

  • A. storing the reading levels 1,2,3,4 in an Array under USERS, once the reader wants to exclude certain levels, then these levels will be removed from their Array
  • B. adding or removing the user.id from BOOKS depending on whether the reader wants to exclude certain level books.

However, with each approach I am unable to define the Streambuilder in such a way that it will only display books for which the reading level is toggled ON. For example, if I used storing approach B (adding/removing user.id from Books), then when I use below code:

stream: FirebaseFirestore.instance
                          .collection('Books')
                          .where('Genre', isEqualTo: 'Fantasy')
                          .where('levelReading1', arrayContains: user?.uid)
                          .where('levelReading2', arrayContains: user?.uid)
                          .where('levelReading3', arrayContains: user?.uid)
                          .where('levelReading4', arrayContains: user?.uid)
                          .orderBy('Timestamp', descending: true)
                          .snapshots(),

it will not work properly because if levelReading1 already does not contain the user.uid, nothing will be displayed.

Does anyone have a good suggestion on how to store the preference of the user and how to subsequent define the Streambuilder so only the relevant books get displayed.

Thank you


Solution

  • I think you're looking for "OR" queries (https://firebase.google.com/docs/firestore/query-data/queries#or_queries). In this case, it should be something like:

    stream: FirebaseFirestore.instance
                              .collection('Books')
                              .where('Genre', isEqualTo: 'Fantasy')
                              .where(Filter.or(
                                Filter('levelReading1', arrayContains: user?.uid),
                                Filter('levelReading2', arrayContains: user?.uid),
                                Filter('levelReading3', arrayContains: user?.uid),
                                Filter('levelReading4', arrayContains: user?.uid),
                              ))
                              .orderBy('Timestamp', descending: true)
                              .snapshots(),