My goal is to effectively get a list of children (ordered* and indexed**) with the lowest number of data transfer.
* ordered: ordered by points for each user / database child
** indexed: 2 or less ranks behind/after the current user [A specific child] (further elaborated below)
My database structure is as follows:-
I basically want to get the first 3 users ordered by points (simple):-
val usersRef = FirebaseDatabase.getInstance(DB_LINK).getReference("users").orderByChild("points")
usersRef.limitToFirst(3).addValueEventListener(
object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (ds in snapshot.children) {
val points: String = snapshot.child("points").getValue(String::class.java)!!
val firstName: String = snapshot.child("firstName").getValue(String::class.java) ?: ""
val uid: String = snapshot.key!!
// Update View
}
}
override fun onCancelled(error: DatabaseError) {}
}
)
Then, provided that the currently logged in user isn't one of the first three, I want to get his rank (order according to points in the whole db), 2 users' before him, and 2 users' after him without querying the whole database (it's a user database that can get up to 50K unique users) because querying the whole database is a really expensive client-side task.
I checked firebase data filtering page but found nothing useful about limiting results according to a certain child.
This answer doesn't satisfy my needs, as it loops over the whole database (in my case, 50K records). I need an effective method as I need to really save these firebase bills.
Moreover, I check this answer but it didn't meet my needs because it still queries the whole database, meaning it is not effective and will be billed for each node before the current user. (Maybe he is number 40,000 in the db, so I shouldn't query the whole db each time to get his rank and get billed for 39,999 reads)
I searched for a way to somehow use booleans to filter queries but again found nothing useful. Here is my not-effective code:-
// Gets all children.
usersRef.addValueEventListener(
object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (ds in snapshot.children) {
val points: String = snapshot.child("points").getValue(String::class.java)!!
val firstName: String = snapshot.child("firstName").getValue(String::class.java) ?: ""
val uid: String = snapshot.key!!
// Update View only if user is `2 <= usersRank - theirRank <= -2`
}
}
override fun onCancelled(error: DatabaseError) {}
}
)
I want to achieve something like this:- (Styling already done, logic remaining)
Is there a way to achieve this? Any alternatives?
EDIT: I found out that firestore offers aggregation queries that may help in this situation. Doing more research to further narrow down the costs.