22

Is there a way to get all documents which array field does not contain one or more values, now there is "array-contains" but is there something like "array-not-contains"?

astro
  • 243
  • 1
  • 2
  • 7

3 Answers3

12

You can only query Firestore based on indexes, so that queries all scale up to search billions of documents without performance problems.

Indexes work by recording values that exist in your data set. An index can't possibly be efficient if it tracks things that don't exist. This is because the universe of non-existant values compared to your data set is extremely large and can't be indexed as such. Querying for non-existence of some value would require a scan of all your documents, and that doesn't scale.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • 14
    I understand your statement, but this also means that somethings are not possible. For example, how show to a user a list of users that he has not seen yet ? Like Tinder, you show people that you haven't "match" yet, and you store people that you match or ignore, but you can't keep records (and make an index) of all people that you haven't match. Even with relative few users (more than 10 thousands) you will already have more than billion recors. I don't know if what I'm saying make sense but I didn't find a way to represent this kind of relationships in Firebase. – FrenchTastic Jan 18 '19 at 12:43
  • 1
    If you want to record an action that hasn't been taken yet, simply assign a known value to indicate that at the time of document creation so that it gets indexed. e.g. `hasDoneSomething = false` Then, when the action is taken, set it to true. You must know ahead of time what you're trying to index. – Doug Stevenson Jan 18 '19 at 17:10
  • dear would you elaborate on the proposition you represented here; `hasDoneSomething = false` approach – Mechanic Oct 27 '20 at 20:57
5

I don't think that is possible at the moment. I would try looking at this blog post for reference.

better arrays in cloud firestore

You might need to convert your array to an object so that you can query by (property === false)Convert array to object

chris
  • 184
  • 5
  • 6
    if the property doesn't exist, even querying with `property === false` won't give a result – Ced Nov 21 '18 at 19:30
  • This will work except if the elements in your array are dynamic with arbitrary values, then if you have queries on multiple fields this will fail due to index issues – l1b3rty Dec 29 '19 at 11:04
0

Considering that your collection will have a low number of documents, you could store all of their ids in another document using an onCreate cloud function trigger, download this document from the client and do the filtering client-side. You could also do all of this inside a cloud function if you're worried about performance.

You'll have 1 extra read but that's no big deal, each document can have up to 1 MB of storage and that's a lot so you shouldn't be worried about it too much, you could also divide those ids into different documents and merge them on the client/cloud function if they get too big.

This works very well for small sets of data, but if you're expecting millions of documents, then there isn't much you can do.

gustavodacrvi
  • 255
  • 3
  • 5