Multiple Where Clauses FireBase Cloud FireStore With Multi Column Indexing

I had a little paywall related issue crop up in SquadWOD the other day, I want to limit the number of challenges a user can make per month to encourage them to upgrade to the paid membership. This is the perfect example of a freemium limit as the more challenges a user makes the more reads and writes they create in the system and in FireBase that literally costs more money.

The query I wanted to make was "how many challenges has this user made in the past month?" Simple enough in SQL, something like:

SELECT 
  * 
FROM 
  challenges 
WHERE 
  user_id == USERID 
  AND created_at > StartOfCurrentMonth;

Having the multiple where clauses SQL makes this quick, simple and fast. However, with AngularFire there is no support for multiple where clauses when querying a FireStore collection like this and so I was left with a few choices:

  1. Get every challenge, from every user, created this month and then filter off the ones for the current user in the JS afterwards. Once the app is popular this would return a lot of challenges.
  2. Get every challenge created by this user ever and then in the JS filter off the current month. Better than the first as the user would be limited in how many challenges that have made each month but, if they have been a user for a year before upgrading this could still be over 100 reads just to get a count of say 5 that I care about, and this would happen every time they click the button to create a challenge.
  3. Keep a counter on their user document that tracks how many challenges they have made this month and then run a cloud function at the start of each month to reset this to 0 for every user. Not a terrible solution, but I'm not a huge fan of scheduled tasks like this as they can be hard to find later unless they are well documented.

Multi-Column Index

None of the above felt great as I really want to minimise how often I need to read from the database so I decided to take advantage of the fact that this is a very predicable search clause "this month, this user, how many records?" and add a multi-column index made up of the creation month and userID.

// add class property
creationFilterIndex: string;

// set index when creating challenge
creationFilterIndex: `${createdAt.format('YYYYMM')}${this.user.id}` 
// eg: 202006udfjhsflienamamdnjfhg

// search on this property in FireBase
getTotalChallengesMadeThisMonth(user: User): Observable {
  return this.db.collection(
    'challenges',
    ref => ref.where('creationFilterIndex',
    '==',
    `${moment().format('YYYYMM')}${user.id}`)
  ).valueChanges().pipe(map(actions => {
    return actions.length;
  }));
}