I am trying to make a dating app, somewhat similar to Tinder, using Firebase Firestore.
There is one interesting DB design problem that I want to solve optimally.
About
Each day, my profile will be shown to a limited number of people (say 100 people) who logged in that day. For now let's forget about the distance and other matching factors, and just consider showing my profile to 100 new random people each day.
Problem
What kind of Firestore DB design would be needed to implement this ?
I do have one idea how to solve this (see below), but it has many cons.
Can you suggest a better idea ?
My Solution so far :
I maintain a firestore collection, where each profile is one document in it. And each profile document maintains a todaysReadCount
field that keeps track of how many times the profile has been read today.
Then use this query to fetch 50 profile for each user :
firestore.collection("Profiles").where('todaysReadCount','<=', 100).limit(50).get();
As soon as the fetch is complete, the client (app) will right away update all these 50 profile documents with todaysReadCount 1
foreach uid_i in fetched50profiles {
firestore.collection("Profiles").doc(uid_i).update({
todaysReadCount: FieldValue.increment(1)
});
}
Every mid-night a cloud function resets this counter in all the profiles.
Theoretically this should work, but there are multiple problems with this approach:
There will be many writes just to maintain the counter. Atleast 100 writes / profile / day. This will increase my firestore bill $$$.
Updating all profile docs at midnight, is also a huge overhead, and will cost $$$.
Since reading the profile and updating their counter is not a single transaction, there will be a delay between reading & updating. This may result in more profile reads than 100, if huge number of people log in simultaneously. (But this is not a big problem irl I guess)
Can you suggest a better solution ?
CodePudding user response:
One thing to reduce the need for nightly clean up would be to store the counters per date, and not just for today. So add a field for each day:
readCount_20200413: 100,
readCount_20200414: 42,
readCount_20200415: 1
While you'll still need to clean these counters up periodically to prevent running over the maximum document size or number of indexes, you can do it at a much lower interval and thus reduce the number of nightly writes.
You will need to pre-seed the count for upcoming dates to 0 with this, as queries will otherwise not return the document if no count is present for a date.
Another improvement would be to store the counters in a system that meets your billing requirements better, and what Dharmaraj commented as a cache. For example, you can keep the counters in the Firebase Realtime Database, which will typically be much cheaper for this use-case.
You can then either query against this alternate data source, or you can check on every write whether the new counter value exceeds your threshold and update the profile in Firestore when it does to exclude it from queries there.
So you'd end up with the counters in Realtime Database, and simpler boolean fields in Firestore, which also means you won't need a range query there.
canShowOn_20200413: false,
canShowOn_20200414: true,
canShowOn_20200415: true
canShowOn_20200416: true
canShowOn_20200417: true