5

I am working with a collection in Firebase that stores information about products. Previously, I was just fetching all of the products and then applying filters to them on the client side. I was told that I need to apply these filters through the query in order to reduce the number of reads that Firebase will need since there will be a very large number of products.

I have tried chaining together multiple .where() statements, but this does not product the effect that I need, I read in another post that multiple .orderBy() statements will break the query, but in order to check the other fields such as price the output tells me I need to orderBy() price first. Any number of these filters could be applied, or none of them could depending on settings. I am using the lastVisible variable at the bottom for a .startAfter in a separate function for getting more products. Is there any way to product the kind of queries I want to make this way? I would also like to know if it is possible to do something like .where('field', isEqualTo: x or y or z).

    Query productQuery = Firestore.instance.collection('Products');

    if(selectedCategories != null)
    for(int i = 0; i < selectedCategories.length; i++)
      productQuery = productQuery.where('category', isEqualTo: selectedCategories[i]);

    if(minPrice > 0 && maxPrice > 0)
    {
      productQuery = productQuery.orderBy('price').where('price', isGreaterThanOrEqualTo: minPrice).where('price', isLessThanOrEqualTo: minPrice);
    }
    else if(minPrice > 0)
      productQuery = productQuery.orderBy('price').where('price', isGreaterThanOrEqualTo: minPrice);

    else if(maxPrice > 0)
      productQuery = productQuery.orderBy('price').where('price', isLessThanOrEqualTo: maxPrice);

    if(!showUnavailableItems)
      productQuery = productQuery.where('status', isEqualTo: 'available');

    switch(selectedCondition)
    {
      case 'Acceptable':
        productQuery = productQuery
                      .where('condition', isEqualTo: 'Acceptable')
                      .where('condition', isEqualTo: 'Good')
                      .where('condition', isEqualTo: 'Very Good');
        break;
      case 'Good':
        productQuery = productQuery
                      .where('condition', isEqualTo: 'Acceptable')
                      .where('condition', isEqualTo: 'Good');
        break;
      case 'Very Good':
        productQuery = productQuery
                      .where('condition', isEqualTo: 'Acceptable');

        break;
      default:
        break;
    }

    productQuery = productQuery.orderBy('id');

    QuerySnapshot myQuery = await productQuery.getDocuments();
    List<DocumentSnapshot> productSnaps = myQuery.documents;
    print("INITIAL PRODUCT SNAPS LENGTH: ${myQuery.documents.length}");

    if(productSnaps.length != 0)
      lastVisible = productSnaps[productSnaps.length -1].data['id'];

When the condition or category filters are applied, the result is always 0 documents. Using the minPrice and maxPrice filters separately works, but together also returns 0 products. I have not gotten any errors besides ones for creating the indexes in Firebase.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Dominic Wasko
  • 165
  • 2
  • 7

1 Answers1

3

I was told that I need to apply these filters through the query in order to reduce the number of reads

That's correct since in Firestore everything is about the number of reads and writes.

I have tried chaining together multiple .where() statements, but this does not produce the effect that I need

Why do you say that? I have used many times the where() function to filter data within a Cloud Firestore database and never failed.

I read in another post that multiple .orderBy() statements will break the query

Is not true! Please check my answer from the following post:

Please also remember that if you are using multiple orderBy() method calls, you get a warning similar to this:

Status{code=FAILED_PRECONDITION, description=The query requires an index.

So don't forget to create an index in your Firebase console.

Is there any way to product the kind of queries I want to make this way?

Yes, you can use all options you already mentioned.

I would also like to know if it is possible to do something like .where('field', isEqualTo: x or y or z).

No, it is not possible but there is a workaround that can help you achieve the same thing. For that, please see my answer from the following post:

So instead of using an array, use a map and chain multiple where() calls.

Static_Subhang
  • 127
  • 1
  • 12
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Thank you for your response. What I mean with the multiple `.where()` statements is that when the switch statement for condition is `Very Good` the query returns all of the products with `Very Good` as the `condition`, but when `Good` is selected I want it to return all products that have the `condition` set as either `Very Good` or `Good`, but when that case runs it always returns 0 products with no error codes. – Dominic Wasko May 31 '19 at 19:49
  • When you want to have a condition to set as either `Very Good` or `Good`, it means that you are looking for a OR clause (in SQL terms), which is currently not supported in Cloud Firestore. For a solution, please see my answer from this **[post](https://stackoverflow.com/questions/55487516/between-startdate-and-enddate-firestore/55489805#55489805)**. – Alex Mamo May 31 '19 at 19:56
  • I was able to rework the data structure of my Firebase document to not require any OR logic based queries. Thank you for the link to the Firebase limitations from your previous post. – Dominic Wasko Jun 01 '19 at 21:14
  • WOW, even doesn't support OR? I'm wondering why so many people are still using Firebase when it even doesn't work for such a common scenario. Can I say the Firebase query is very weak? – Bagusflyer Jun 02 '20 at 07:39
  • @Bagusflyer This answer is from 2019. Now, in 2020 we have an option to use [10 equality (==) clauses on the same field with a logical OR](https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any) ;) – Alex Mamo Jun 02 '20 at 09:30
  • @Alex Mamo Thanks for clarify. I'm wondering if it's possible to search for a field contains certain string. For example, I want to search all clients whose name contains 'abc'. – Bagusflyer Jun 02 '20 at 15:10
  • @Bagusflyer Check [this](https://stackoverflow.com/questions/52627194/search-by-pattern-on-cloud-firestore-collection/52627798) out. – Alex Mamo Jun 02 '20 at 15:44
  • @Alex Mamo Thanks. Your solution is great. But it's only possible to search by `startWith` instead of `contain` and not possible to search case insensitive. Is it possible to search for example startWith `abc` or `Abc`? – Bagusflyer Jun 03 '20 at 02:11
  • @Bagusflyer Maybe this [answer](https://stackoverflow.com/questions/56386816/firebase-complex-queries-in-flutter/56393764?noredirect=1#comment109943769_56393764) will also help. – Alex Mamo Jun 03 '20 at 08:06