Yussuf
Yussuf

Reputation: 302

Filtering by multiple fields using Firestore

To put simply. It is a filtering problem that i am having with Firestore. Take this model as an example:

Collection: Room
   - Document#1
      - query_role: Array - Limit 10
      - query_user: Array - Limit 10
      - players: Array<Object> [{
             playerId: string
             user: Object<id, firstname, lastname, ...>
             role: Object<id, name, ...>
         }]
      ...

My application has a page called rooms that anyone could use to search for (you guessed it) rooms.

With filters to narrow down the type of room they can enter but for this example, we'll just use role as the only filter. Simple stuff or so I thought.

The logic behind the search/filter page are to:

  1. Find all rooms that still have space in them
  2. Use the filter to find rooms that still have a certain role in them (e.g. Mafia, Doctor, Villager, etc...) that aren't assigned to any users
Collection: Room
   - Document#1
      - query_role: ['111', '222', '333', '333']
      - query_user: ['user1', 'user2', 'user3', false, false, false, false, false, false, false]
      - players: [{
             playerId: 'djs123d21sSd213r'
             user: null
             role: {
                id: '111',
                value: 'Mafia'
                ...                
             },
             ...
         }]
      ...

Every role that is created for this room is inserted into the players->role with the user set to null. The role is then inserted into query_roles to use as a filter on the page if a user chooses to search by available roles:

.where('query_roles', 'array-contains', role)

Now the problem is, with firestore. You can only use array-contains once in a query. I keep getting errors like this: A maximum of 1 \'ARRAY_CONTAINS\' filter is allowed.'. The other array-contains as i've mentioned before, is being used on query_users to find rooms that still have space by doing:

.where('query_user`, 'array-contains', false)

I cant put them in an object like so:

{
 user1: true,
 user2: true,
 false: true,
 false :true
}

since all of those false would slap into one field and it would be the same with roles. Since there can be multiple roles that are the same, it would merge into one field.

The only way I can think of is manually setting up a flag that says full: true|false that will be used to determine if a room is full or not. I'd still need to use the query_user because in the application i use it to search for all Rooms a specific user is in.

I am writing to see if there are any alternative ways anyone else can think of without messing about with creating flags. Long question, but I appreciate you reading up until here.

Upvotes: 0

Views: 981

Answers (1)

Alex Mamo
Alex Mamo

Reputation: 138824

Find all rooms that still have space in them

To solve this you can simply add into your room document two new properties. One would be named numberOfRoles and the other one numberOfUsers. Once you add a new role to the query_role array increase the value of numberOfRoles by one and every time you add a new user to the query_user array increase the value of numberOfUsers by one. In this way you can simply query your rooms collection using:

roomsRef.where('numberOfRoles', '<=', 10).where('numberOfUsers', '<=', 10)

Chaning multimple array-contains functions is not allowed in Coud Firestore but chaining multiple where() calls will work perfectly fine.

Use the filter to find rooms that still have a certain role in them (e.g. Mafia, Doctor, Villager, etc...) that aren't assigned to any users

Once you get a positive result from the above query then you can get the content of your query_role array and see the available rolls.

Every role that is created for this room is inserted into the players->role with the user set to null.

There's no need for that anymore.

The only way i can think of is manually setting up a flag that says full: true|false that will be used to determine if a room is full or not. I'd still need to use the query_user because in the application i use it to search for all Rooms a specific user is in.

Setting a flag to true|false will not solve your entire problem. Please note that if you want to search for a specific user in the query_user array you can still do that since you perform only a single query using the array-contains operator.

Upvotes: 1

Related Questions