Search code examples
angularfirebasegoogle-cloud-firestoreangularfire

How to filter by dynamic object properties in Angularfire


I have a model like below in Angular + AngularFire + Firestore project

export interface Game {
    id: string;
    ... some other properties
    players: Array<{
       userId: string;
       name: string;
       picture: string;
    }>;
    playerIds: { [userId: string]: boolean };
}

and data look like this

enter image description here

Now I want to query all records where a specific userId is one of the players.

since I want to only filter by userId (not whole player object), I can not use array-contain, so I added a playerIds property which is a map object.

and my code is like


    this.collection((ref) => ref.where(`playerIds.${user.id}`, '==', true).where(`status`, '!=', GameStatus.Started)).valueChanges(),

Then it asked me to create an index for this query. The issue is the index is very specific for that user, and it's included that specific user id.

enter image description here

In my other project using firebase in nodejs I have done same thing over and over, but seems in AngularFire it's different.

I know if I change it to array of userIds I can query by array-contains, my question is why this is not working and how make it work.


Solution

  • The playerIds field you have in your screenshot is not an array, but a map with the keys bTr2... and lnm4... and the values being true. Unfortunately you'll need a separate index for each field in that map.

    To be able to use a single index, turn the playerIds field into an actual array:

    playerIds: ["bTr2...", "lnm4..."]
    

    With this structure, you:

    • Only need a single index, on the playerIds field.
    • Can query with array-contains.
    • Can add items to the array with arrayUnion.
    • Remove items from the array with arrayRemove.

    Also see the documentation on updating elements in an array.