3

I have a collection the docs of which have an array property members which contains user IDs. I need to find the docs the members of which are a pair of user IDs, eg.:

enter image description here

From the docs for compound queries I can see how to make an OR, but I need an AND, because I need the docs that contain both user IDs (which actually is what makes a doc unique). The docs say that

you can include at most one array-contains or array-contains-any clause in a compound query

so, the following code doesn't work (I tested and it actually returns an error):

const conversation = await firebaseDb.collection(collectionName)
      .where('members', 'array-contains', userId)
      .where('members', 'array-contains', otherUserId)
      .get();

I tried this as well:

const conversation = await firebaseDb.collection(collectionName)
      .where('members', 'array-contains', [userId, otherUserId])
      .get();

but it returns nothing.

Is it actually possible to perform a logical AND on array values in a Firestore doc?

Milkncookiez
  • 6,817
  • 10
  • 57
  • 96

1 Answers1

6

The simplest solution I can think of is to store those IDs into a Map and not into an array. So your members Map should look like this:

members
 |
 --- M1fB...szi1: true
 |
 --- wXam...69A2: true

Now you can simply query using:

const conversation = await firebaseDb.collection(collectionName)
  .where('members.' + userId, '==', true)
  .where('members.' + otherUserId, '==', true)
  .get();

And this is indeed an AND operation.

Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • you'll run into indexing issues because firestore has to create an index for every uid. only 200 indexes allowed. also, these members are dynamic so no point in creating a map – Timmy Simons May 03 '21 at 15:26
  • @TimmySimons That's not correct, there is no need for any index in case of such a Query. – Alex Mamo May 04 '21 at 08:59
  • I actually just did the described approach and firestore returns a different index creation link for each combination of filters – Ali H. Kudeir Jul 06 '21 at 22:16
  • @decoder That's the expected behavior. Each index has a different creation URL. – Alex Mamo Jul 07 '21 at 06:39
  • @AlexMamo, I commented because you've mentioned there is no need for an index for such a query, though in my case it did not succeed, I solved it, by leaving OR filtering in the backend then applying logical AND filtering on the paginated result in the frontend. – Ali H. Kudeir Jul 07 '21 at 13:10
  • 1
    @decoder You need an index only if you order the results. – Alex Mamo Jul 07 '21 at 13:13
  • That is correct, I just tried it and it works great :D. Thanks @AlexMamo – Ali H. Kudeir Jul 07 '21 at 14:15