Firebase Realtime Database Unity中混合类型分数按数值排序求助
解决Firebase实时数据库混合类型分数的排序问题
Firebase实时数据库的OrderByChild是按类型优先级+值排序的:数字类型优先级高于字符串,所以会出现数字在后、字符串在前的结果,这是原生排序规则导致的。针对你用字符串存储超大数值的场景,给你两种可行的解决方案:
方案一:客户端获取数据后统一转换排序
这种方式适合数据量不大的场景,把所有分数统一转为数值类型后再排序:
1. 定义数据模型
先创建一个类来存储玩家的ID和转换后的分数:
using System.Numerics; // 如果用BigInteger需要引用这个命名空间 public class PlayerRank { public string Id { get; set; } public BigInteger Score { get; set; } // 用BigInteger支持超大数值 }
2. 解析快照并排序
获取到数据快照后,遍历所有子节点,把不同类型的score统一转为BigInteger,再用LINQ排序:
// 假设snapshot是你从Firebase获取到的数据快照 List<PlayerRank> rankList = new List<PlayerRank>(); foreach (DataSnapshot child in snapshot.Children) { string playerId = child.Key; object scoreObj = child.Child("score").Value; BigInteger score = BigInteger.Zero; // 处理数字类型的score if (scoreObj is long numScore) { score = numScore; } // 处理字符串类型的超大数值 else if (scoreObj is string strScore) { if (!BigInteger.TryParse(strScore, out score)) { Debug.LogWarning($"跳过无效分数:玩家{playerId}的分数{strScore}无法转换为数值"); continue; } } // 其他未知类型直接跳过 else { Debug.LogWarning($"跳过未知类型分数:玩家{playerId}的分数类型无效"); continue; } rankList.Add(new PlayerRank { Id = playerId, Score = score }); } // 按分数从大到小排序 var sortedRank = rankList.OrderByDescending(p => p.Score).ToList(); // 输出排序结果 foreach (var player in sortedRank) { Debug.Log($"[{player.Score}] 玩家ID:{player.Id}"); }
方案二:优化存储方式,让服务器端直接排序
如果数据量较大,客户端排序性能不足,可以统一将分数存储为固定长度的补零字符串,让字符串排序的结果和数值排序一致:
比如所有分数都转为20位长度的字符串,数值不足的前面补0:
- 数值123 →
"00000000000000000123" - 数值99999999999999999999 →
"99999999999999999999"
这样用dbReference.OrderByChild("score").LimitToLast(100)就能直接获取前100名(因为字符串升序的最后几个就是数值最大的),不需要客户端二次排序。
注意事项
- 如果使用
BigInteger,记得在Unity的Player Settings里勾选"Allow 'unsafe' code"(如果需要的话),并确保导入System.Numerics程序集。 - 补零字符串的长度要根据你需要存储的最大数值位数来设定,确保所有数值都能覆盖。
内容的提问来源于stack exchange,提问作者Ariel Developer
相关产品推荐
相关产品推荐

