简体   繁体   中英

Firebase Complex Queries In Flutter

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM