我在Firestore中有1万个用户,每个用户的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中的问题?
答案 0 :(得分:0)
您可以使用startAfter
/ startAt
并提供文档参考来抵消您的查询。
因此,如果您有前二十条记录的列表,则可以重复进行完全相同的查询,但是将其startAfter
指定为列表中的最后一个元素,则将返回位置{{1 }}到20
等
您还可以将查询39
设置为返回将返回到设定位置的结果,但是强烈建议不要这样做,因为使用offset
时,您会为跳过的每个文档产生一个写操作。因此,如果您想获取排名前20位的播放器,最终将需要等待9,980次文档读取!
您可以查看Paginate data with query cursors以获得更多信息。
就您现有的数据结构而言...
要通过用户标识符找出用户的排名,可能需要手动缓存其当前排名。您可以设置计划任务来计算玩家的排名,并每天计算每个玩家的排名。这将是昂贵的,因为每次执行的写入数量将随用户数量的增加而增加。并且由于它是基于缓存的,因此受时间限制(玩家在下次计算时不会看到他们的排名变化。)
一种更简单的方法是采用最高得分,最低得分,并根据用户数量将其得分缩放到同等等级(这不一定是线性缩放,您可以使用例如钟形曲线),但是这可能不够精确,并且可能导致多个用户看起来具有相同的排名。但是,根据您的用例,这可能是一个合适的让步。
另一种方法是让用户在尝试查看自己的排名时自行更新排名系统。它可以查看在其之前和之后的用户点,并通过确定该记录是否应成为相邻记录之前或之后,有效地维护自己的排名。这将需要更精细的规则结构来防止作弊,并且会在排名数据集中引入不连续性。