3

I'm playing with the recently introduced Cloud Firestore and I was wondering if it's possible to get a document's index in a collection to create a leaderboard.

For example, let's say I want to retrieve a user's position in the leaderboard. I'd do something like this:

db.collection('leaderboard').doc('usedId')

There, I'd have a rank field to display that user's position in the leaderboard. However, that means I'd have to create a Cloud Function to calculate users' position everytime their score changes. Considering Firestore charges by the number of CRUD operations, that could be really expensive.

Is there a better way to do it? Let's say define a query field (i.e. score), then get that document's index in the collection's array?

Will
  • 2,523
  • 1
  • 13
  • 21
  • For users coming recently to this question, this one might offer a better help for this issue: https://stackoverflow.com/questions/46720997/leaderboard-ranking-with-firebase – Will Nov 22 '17 at 01:22

2 Answers2

2

You can't find the position of a document within a query result except by actually running the query and reading all of them. This makes sorting by score unworkable for just determining rank.

You could reduce the number of writes for updating ranks by grouping ranks into blocks of 10 or 100 and then only updating the rank group when a player moves between them. Absolute rank could be determined by sorting by score within the group.

If you stored these rank groups as single documents this could result in significant savings.

Note that as you increase the number of writers to a document this increases contention so you'd need to balance group size against expected score submission rates to get the result you want.

The techniques in aggregation queries could be adapted to this problem but they essentially have the same cost trade-off you described in your question.

Gil Gilbert
  • 7,722
  • 3
  • 24
  • 25
0

You can filter it in the database console. Top-right of the centre column, next to the 3 vertical dots.

You can also use this GitHub Repo to search for the query you need to insert into your code: https://github.com/firebase/snippets-web/blob/f61ee63d407f4a71ef9e677284c292b0a083d723/firestore/test.firestore.js#L928-L928

If you wanted to rank users based on their 'highScores', for instance, you could use something like the following for the top 10 (and create an ordered list or similar, to represent the user's rank):

db.collection("leaderboard")
.orderBy("highScore", "desc").limit(10)  // this is the line you add to filter results
.get()
.then((snapshot) => {
  snapshot.docs.forEach((doc) => {
    console.log(doc.data()); 

    renderLeaderboard(doc);
  });
});
Robert Yeomans
  • 192
  • 1
  • 4