2

I have a Firestore document that contains array like this:

Array:                    Array:
[1, 2, 3, 4, 5, 6, 7] or ['Zhangir', 'Erasyl', 'Arman']

And I need to check if this document contains any of given arrays. For Example:

[1, 2, 3, 4] or [1, 2, 7] or ['Zhangir', 'Arman'] and so on

and return it only if it has exact matches. But considering that my arrays can be 100 elements long, that would be very inconvenient to say arraycontains [1], arraycontains[2]... each time. Is there any way to do a compound query for a lot of values? All information that I found says I can't, but maybe there's a way.

From my example that would be

Firestore.instance.collection("Querys")
.where('array', arrayContains: [1, 2, 3, 4, 5]);

or

Firestore.instance.collection('Querys')
.where('array', arrayContains: ['Zhangir', 'Arman']);

and not something like

Firestore.instance.collection('Querys')
.where('array', arrayContains: 'Zhangir')
.where('array', arrayContains: 'Arman');
Zhangir Siranov
  • 439
  • 1
  • 5
  • 14
  • `docRef.where("myArray", ">=", 1).where("myArray", "<=", 4);` where `docRef` is the reference pointing to your document, and `myArray` is your array field within your document. More info can be found on the [documentation for compound queries](https://firebase.google.com/docs/firestore/query-data/queries#compound_queries) – sllopis Dec 02 '19 at 10:02
  • @sloppis, it doesn't necessarily has to be 1, 2, 3, 4, it can be any given length and any given sequence, for example [3, 6] or [1, 2, 7] and so on. I updated the question – Zhangir Siranov Dec 02 '19 at 10:06
  • Hi @ZhangirSiranov, the previous solution would only work for a range of sequences, and you will need to create a composite index. On the other hand, for your current use case, I would suggest to use the `array-contains-any` operator to combine up to 10 array-contains clauses on the same field with a logical OR. More info can be found [here](https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any). Notice that there is a small difference between `in` and `array-contains-any` operators, since `in` matches for an exact match of array length, order, and values. – sllopis Dec 02 '19 at 10:38
  • @sllopis, but with that I will have to go through a lot of unwanted documents, increasing the size of the query. – Zhangir Siranov Dec 02 '19 at 10:41
  • @sllopis, because array-contains-any looks for only one element that satisfies the test – Zhangir Siranov Dec 02 '19 at 10:43
  • As per [documentation](https://firebase.google.com/docs/firestore/query-data/queries#limitations), `in` and `array-contains-any` support up to 10 comparison values. In your example, you would like to filter out certain values in your array and fetch only those values that meet a certain criteria. If you are concerned about your database going through its content item by item, you can use an [index](https://firebase.google.com/docs/firestore/query-data/index-overview#single-field-indexes). – sllopis Dec 02 '19 at 10:58
  • `in` operator matches for an exact match of array length, order, and values, which is slightly different from the `array-contains-any` operator. Therefore, you could use something like: `docRef.where('array', 'in', [['Zhangir', 'Arman']]);` Hope this helps a bit. – sllopis Dec 02 '19 at 11:00
  • @sloppis, thank you for your help, but It seems that available methods are not capable of what I want to do. There is no way of finding if small array is somewhere in bigger array as I wanted that to be – Zhangir Siranov Dec 02 '19 at 11:30

1 Answers1

7

Firestore can now check for these condition on array fields:

  • Whether the field contains a specific value with array-contains.
  • Whether the field contains any of a list of (up to 10) values with array-contains-any.

What you're describing is an array-contains-all like operation, which currently doesn't exist. And you can't create it by combining multiple array-contains checks, as you can only have one of those in a query. You might want to file a feature request for it.

The best option today are to:

  1. Pick one value from the array, and perform an array-contains query with that value. Then you do the additional filtering in your application code.
  2. Use a map to store the values, and then use multiple where value == true conditions, as shown in the answer to this question: Firestore: Multiple 'array-contains'
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks sir, but I'm afraid that I will have to query a lot of documents If I do it this way. I'm going to go with different solution though, but still thanks. – Zhangir Siranov Dec 02 '19 at 16:14