Florian Ldt
Florian Ldt

Reputation: 1235

Reduce read usage on Firestore

We are currently using the free tier on Firebase, with a quota of 50k read and 20k write operations.

With around 100 daily users, we are already over quota on the read operations. The structure of the Firestore is the following:

Firestore-root
    |
    --- steps (collection)
    |   |
    |   --- 20191206 (document)
    |       |
    |       --- users (collection)
    |           |
    |           --- 08yzYycNqYMZw7kdeGBNV9jcg1G2 (document)
    |               |
    |               --- country: "FR"
    |               |
    |               --- name: "florian"
    |               |
    |               --- steps: 24
    |               |
    |               --- updated_at: "2019-12-05T20:25:05Z"

The application displays a list of users ordered by their number of steps.

So as a simple calculation, at every app launch, if x equals the number of user entries stored in the users collection, x+1 documents should be read representing x+1 read operations. For 100 users opening the app and 100 users entries, It should be already 10100 read operations (~20% of the daily quota).

Am I right on my read operation calculations? (if 1 read operation = 1 read document).

On the other hand, is there a way to optimize the Firestore structure to reduce the number of document read?

We currently have a patch that use the .limit() operation to avoid selecting all the entries to free some read operation but it's not a permanent solution here.

Having all the step data in one document also seems a bad solution since each document must have a size < 1MB. It can be a solution for some time but will also be a limitation if the user base is growing.

Thank you for your suggestions on this.


EDIT 2019/12/06 #1

Here are the queries (for iOS here) used on the steps collection.

db
    .collection("steps")
    .document(date.string)
    .collection("users")
    .whereField("steps", isGreaterThan: 0)
    .order(by: "steps", descending: true)
    .getDocuments { }

db
    .collection("steps")
    .document(date.string)
    .collection("users")
    .document(uid)
    .setData([
        "steps": steps,
        "name": name,
        "country": country,
        "updated_at": Date.NowISO8601,
    ])

Upvotes: 1

Views: 2030

Answers (1)

Waelmas
Waelmas

Reputation: 1962

According to Firebase official documentation, you are charged per document read, write and delete. So your calculations seem okay.

Based on the number of users, you might need to consider moving to a paid plan. Possibly the Flame Plan.

However, here is a suggestion to minimize the charges:

Since you are talking about something like a leader-board based on number of steps, I assume that you don't really need updates every few seconds.

What I would do, is make the queries once every specific time-frame and store the values in Cloud Storage where you are charged for storage size instead of read/writes (you get 5GB/month free). Then let your app get the data from Cloud Storage.

This way you will have a constant amount of reads no matter of the number of users you have.

For example:

100 users & updating the leader-board once every 10 mins

100 x (24x60 / 10) = 14.4K reads/day

Depending on your use-case, you might be able to follow a similar logic for writes as well.

Upvotes: 2

Related Questions