6

My use case involves filtering the Firestore documents with 'array-contains-all' whose name I made up for the purpose of this question. However, the 'array-contains-any' already exists, but it does not check whether all the elements are present in the array, but any. I struggle to find an in-built solution or find a better approach to achieve the same result rather than querying all the documents (expensive) and then filtering the result in the Cloud Function before the final array gets passed to the client.

To give an example, we are wondering which accommodation sites have all of the following facilities that we're interested in and wish to query:

[
    'lockable_bedroom_door',
    'private_bathroom',
    'internet',
    'desk',
    'safe_place_to_store_valuables'
]

out of the array of all 13 available facilities:

[
    'kettle',
    'microwave',
    'cooker',
    'washing_machine',
    'fully_functional_kitchen',
    'lockable_bedroom_door',
    'private_bathroom',
    'shared_bathroom',
    'internet',
    'desk',
    'common_room_lounge',
    'safe_place_to_store_valuables',
    'free_on-site_parking'
]

How can it be achieved with keeping in mind both the Firestore limitations and the number of facilities that the user may possibly choose?

2
  • 1
    I've made feature request about this to Firebase team, hope they will implement this. Commented Jun 1, 2023 at 13:32
  • 1
    vote for the feature here - issuetracker.google.com/issues/220676303?pli=1. Maybe this would help to rise it's priority. Commented Dec 18, 2023 at 11:55

2 Answers 2

8

As long as you are working with list type fields as you are now, there isn't going to be a way to query that you would find efficient. If you copy the data into a new map type field, it will be possible.

facilities: {
    'kettle': true
    'microwave': true
    'cooker': true
}

With this map containing known boolean values, you can query like this:

firestore
    .collection("your-collection")
    .where("facilities.kettle", "==", true)
    .where("facilities.microwave", "==", true)
    .where("facilities.cooker", "==", true)
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for the answer Doug! Do you know whether there is any limitation to the number of where queries with '==' operator that can be used in a single query? I have in mind possibly more than 10 facilities that a user may wish to have included in each accommodation. If not, that would be a perfect solution requiring the subtle change you outlined above.
All limits of the system are documented. If you don't see it there, then there is no known limit. firebase.google.com/docs/firestore/quotas
Will this require us to configure Firestore to index the fields within facilities?
this will require an index for every key under facilities .... come on firebase ... you can do better than that !!!
How do we add the where clauses dynamically?
|
1

maybe this can help, I implemented a workarround for this

// generate all every combinasons possibles
fun generateTags(list: List<String>): List<String> {
    val combinations = mutableListOf<String>()

    val size = list.size
    val maxMask = (1 shl size) - 1

    for (mask in 1..maxMask) {
        val current = mutableListOf<String>()
        for (i in 0 until size) {
            if ((mask and (1 shl i)) != 0) {
                current.add(list[i])
            }
        }
        combinations.add(current.joinToString("_"))
    }

    return combinations
}

save the result in an array field and then use WhereArrayContains(Field, list.joinToString("_")) in your query. the list ordering items is important.

sorry for my English, i speak only french.

1 Comment

can you explain your code and estimate the size of such index giving the length of the input list?

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.