首页 > 解决方案 > 在 Firestore 中获得玩家的排名

问题描述

我在 Firestore 中有 10k 个用户,每个用户的 documentId 是他们的 uid,并且分数已注册到他们的文档中。查找排行榜前 20 名,根据其分数成功查询前 20 名用户,如使用复合索引。

let query = usersRef.order(by: scores, descending: true).limit(to: 20)
query.getDocuments() //to get 20 documents

不幸的是,我找不到一种方法来处理当前未进入前 20 名的玩家的排名(索引号)。为什么 Firestore 不根据每个用户的 uid 返回查询的排名(索引号)?或任何其他方式来解决 Firestore 中的问题?

标签: firebasegoogle-cloud-firestore

解决方案


您可以使用startAfter/startAt并提供文档参考来抵消您的查询。

因此,如果您有前 20 条记录的列表,您可以重复完全相同的查询,但将其指定为startAfter列表中的最后一个元素,然后您将返回位置记录2039等等。

您还可以将查询设置offset为返回将在设置位置返回的结果,但是这是非常不推荐的,因为使用offset,您会为您跳过的每个文档进行写入。因此,如果您想获取最后 20 名玩家,您最终将等待 9,980 次文档读取!

您可以查看使用查询游标对数据进行分页以获取更多信息。

就您现有的数据结构而言...

要通过用户标识符找出用户的排名,您可能需要手动缓存他们当前的排名。你可以设置一个定时任务来计算玩家的排名,每天计算每个玩家的排名。这将是昂贵的,因为每次执行的写入次数会随着您的用户数量而增加;并且由于它是基于缓存的,受时间限制(玩家在下次计算之前不会看到他们的排名变化。)

一种更简单的方法是取最高分、最低分,并根据用户数量将他们的分数缩放到同等排名(这不一定是线性比例,您可以使用钟形曲线例如),但是这将是不精确的,并且多个用户可能看起来具有相同的排名。但是,根据您的用例,这可能是一个合适的让步。

另一种方法是让用户在尝试查看自己的排名时自己更新排名系统。它可以查看在它之前和在它下面的用户的点,并通过确定它应该在相邻记录之前还是之后来有效地保持等级。这将需要更精细的规则结构来防止作弊,并且会在您的排名数据集中引入不连续性。


推荐阅读