1

In my app, I have a multiple-choice dialog with various filter options that the user should be able to choose in order to filter the database based on the rarity field of the documents. Since there are many options in the filter dialog, covering each case by hand would take ages if we take into account all the possible combinations of the filters. With that in mind, I tried creating a starting query as you can see below and then I iterate through the list of filters selected by the user and try to add a whereEqualTo("rarity",filter) operation to the query for each filter. I noticed that you can't concatenate queries like with normal variables e.g. var i += 5 so i would like to know if there is any solution to this kind of issue. Can you actually apply multiple whereEqualTo operations in the same query in steps/pieces without overriding the previously applied operations on that same query?

Here's what I've tried after receiving the filters selected by the user in my FilterActivity.kt class:

class FilterActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_filter)

        val db = FirebaseFirestore.getInstance()

        val filters:ArrayList<String>? = intent.getStringArrayListExtra("filterOptions")
        Log.d("FilterActivity", "filter options $filters")

        var query = db.collection("Cards").orderBy("resID")

        for(filter in filters!!) {
            query = query.whereEqualTo("rarity",filter)
        }

        query.get().addOnSuccessListener { querySnapshot ->
            if(querySnapshot.isEmpty) Log.d("FilterActivity","is empty")
            for(doc in querySnapshot.documents) {
                Log.d("FilterActivity", "${doc.getString("name")} - ${doc.getString("rarity")}")
            }
        }
    }
}
Stelios Papamichail
  • 955
  • 2
  • 19
  • 57
  • You chain as may whereEqualTo operations as you need. But what's wrong with this code? – Alex Mamo Dec 17 '19 at 10:57
  • I get errors from the IDE before compilation when i try to use the += operators on the query object but i can't see the error popup window because it's blinking too fast and non stoo for some reason – Stelios Papamichail Dec 17 '19 at 11:05
  • If the app crashes, there is a stack trace. Please look that up on logcat, and add it to your question. – Alex Mamo Dec 17 '19 at 11:05
  • @AlexMamo the issue is that the app won't even run due to the += operator on the query. I'm updating my post with the log from Run – Stelios Papamichail Dec 17 '19 at 13:43

2 Answers2

1

Basically you are trying a do OR operation, where you are retrieving all documents, in which rarity fields matched any of the value in array.

You are try new firebase whereIn operation where you can pass array of values, but theres a limitation of max 10 values in filter

 FirebaseFirestore.getInstance()
            .collection("Cards")
            .orderBy("resID")
            .whereIn("rarity",filters!!.toList())
            .get().addOnSuccessListener { querySnapshot ->
                if (querySnapshot.isEmpty) Log.d("FilterActivity", "is empty")
                for (doc in querySnapshot.documents) {
                    Log.d("FilterActivity", "${doc.getString("name")} - ${doc.getString("rarity")}")
                }
            }

filters arraylist can contain max 10 values

ked
  • 2,426
  • 21
  • 24
0

Can you chain multiple whereEqualTo operations in one query in pieces in Firestore

You can chain as may whereEqualTo operations as you need.

The problem in your code += operator. There is no way you can make an addition/concatenation of two Query objects. To solve this, please change the following line of code:

query += query.whereEqualTo("rarity",filter)

to

query = query.whereEqualTo("rarity",filter)
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Will each run of the if block in my code overwrite the previous whereEqualTo operation or does it get implicitly concatenated? – Stelios Papamichail Dec 17 '19 at 13:54
  • It adds another call to `whereEqualTo`. Give it a try. – Alex Mamo Dec 17 '19 at 14:01
  • This was one of the first things i tried when i came across the += issue but when i tried doing `query = query.whereEqualTo("rarity",filter)` the results from the query.get() are always empty. I tried it again just in case but still no results. Shouldn't this code return all the documents that have a "rarity" value of either "R" or "N" if i were to select the R & N filters? – Stelios Papamichail Dec 17 '19 at 14:21
  • If you select "R" or "N", you'll have either a filter with "R" or "N". If you want both filters, then you should add both `whereEqualTo` calls. But remember, [Firestore queries are immutable](https://stackoverflow.com/questions/54511674/firestore-date-query-not-working-as-expected/54512473#54512473). – Alex Mamo Dec 17 '19 at 14:38
  • Yeah i'd like to be able to apply all the user selected filters at once so in this case both R & N. Since the queries are immutable and i can't concatenate them, in order to cover all the possible combinations of filters, is the only solution to write them by hand in a huge if statement for example? – Stelios Papamichail Dec 17 '19 at 14:45
  • Just create a global query and add `whereEqualTo` calls according to the filters that are selected. In the end, you should have a query that has two `whereEqualTo` calls, right? I don't think there is a concrete example. You should write your own code. – Alex Mamo Dec 17 '19 at 14:48
  • Sorry i'm having some trouble understanding the logic here. Let's say i did the following : var query = db.collection("Cards").orderBy("resID") for(filter in filters!!) { query.whereEqualTo("rarity",filter) } and the filters arraylist had "R" & "N" in it. The for-each loop will run twice but does that count as doing `query.whereEqualTo("rarity","R").whereEqualTo("rarity","N")` ? – Stelios Papamichail Dec 17 '19 at 15:03
  • As long as you are using inside the look `query = query.whereEqualTo("rarity",filter)`, it will works as `query.whereEqualTo("rarity","R").whereEqualTo("rarity","N")`. Every new `whereEqualTo` call should be saved in a new Query object. Does it work now? – Alex Mamo Dec 17 '19 at 15:14
  • I've done that but it still returns an empty query snapshot. I've updated my code on the post too if you're interested. I know for a fact that in my database i have variorus documents that have a rarity value of "R" and other various documents with a rarity value of "N" but instead of returning all of these, it returns an empty query snapshot. – Stelios Papamichail Dec 17 '19 at 15:21
  • It's empty because you didn't create a [Firestore index](https://stackoverflow.com/questions/50305328/firestore-whereequalto-orderby-and-limit1-not-working). If you create it, does it work now? – Alex Mamo Dec 17 '19 at 15:31
  • I have the following composite indexes in firebase : resID Ascending rarity Ascending and vice verca – Stelios Papamichail Dec 17 '19 at 15:43
  • You need to have also an index for the combined `whereEqualTo` calls. If you create that combined index, does it work? – Alex Mamo Dec 17 '19 at 15:56
  • How do i create such an index? The composite index only allows different fields. – Stelios Papamichail Dec 17 '19 at 15:58
  • In that case, you should remove the call to orderBy and then no index is needed anymore. That's a request that should be sent to the Firebase team. – Alex Mamo Dec 17 '19 at 16:03
  • If i remove the orderBy call then the query variable turns into a CollectionReference one. There's bound to be a solution for this out there, i'll probably add a bounty later on and hope someone has faced this before and knows of a workaround :) . Thank you very much for taking so much time to help me out – Stelios Papamichail Dec 17 '19 at 16:08