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.

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

9 Comments

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.
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.
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.
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 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 ;)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.