使用queryOrderedByChild获取最高得分列表时,如何以正确的顺序显示并列得分?

时间:2019-05-12 20:56:50

标签: swift firebase

我的应用程序有一个最高得分表,该表使用.queryOrdered(byChild:“ userHighScore”)和.queryLimited(toLast:100)来获得最高100分:

func getTopScores() {
    var scores = [String]()

    self.reference
        .child("users")
        .queryOrdered(byChild: "userHighScore")
        .queryLimited(toLast: 100)
        .observeSingleEvent(of: .value, with: { (snapshot) in

            for child in snapshot.children.reversed() {

                if let dataSnapshot = child as? DataSnapshot, let user = dataSnapshot.value as? [String:AnyObject] {

                    if let userHighScore = user["userHighScore"] as? Int {
                        var stringToAppend = "\(scores.count+1). "


                        if let userName = user["userName"] as? String {
                            stringToAppend += " \(userName)   •  \(userHighScore)"
                        }

                        scores.append(stringToAppend)
                    }
                }
            }
        })
    }

问题是当平局得分时。

理想情况下,第一个获得该分数的用户将高于表上具有相同分数的其他用户(而获得该分数的最新用户将是得分相同的用户中最低的)。

但是,该表以与Firebase Realtime数据库中出现的随机顺序相同的顺序显示得分相同的得分。

有没有办法按时间顺序对比分进行排序?

我已经为此花了好几个小时。预先感谢您的帮助!

2 个答案:

答案 0 :(得分:6)

  

理想情况下,第一个获得该分数的用户将在表上具有相同分数的其他用户之上

您实质上是在尝试订购两个属性:userHighScoreuserHighScoreTimestamp(我起了一个名字,因为您没有在问题中指定它)。 Firebase实时数据库只能查询单个属性。参见Query based on multiple where clauses in Firebase

您可以 做的是定义一个附加属性,该属性将高分值和已完成的时间戳相结合:

users: {
  derenceUid: {
    userHighScore: 42,
    userHighScoreTimestamp: 1557695609344,
    userHighScore_Timestamp: "000042_1557695609344",
  },
  dougUid: {
    userHighScore: 31,
    userHighScoreTimestamp: 1557609264895,
    userHighScore_Timestamp: "000005_1557609264895",
  },
  pufUid: {
    userHighScore: 42,
    userHighScoreTimestamp: 1557695651730,
    userHighScore_Timestamp: "000042_1557695651730",
  }
}

通过这种结构,您可以通过以下方式获得得分最高的用户:

ref.queryOrdered(byChild: "userHighScore_Timestamp"). queryLimited(toLast: 1)

需要注意的一件事是,我将用户的高分填充为六位数。这是必要的,因为Firebase将对这些键进行字典比较,并且如果没有填充"5_1557609264895"会比"42_1557695609344"大。您必须弄清楚最高分数可以保留几位数。在我的示例中,我使用了6位数字,因此它最多可以保存100万个分数。

答案 1 :(得分:1)

理想地,您需要的是orderByChild两个值,分别是score和date。据我所知,Firebase实时数据库不支持该功能。我可以提出两种选择:

  1. 存储分数不是作为字符串而是作为对象,包括两个值:“得分”和“时间戳”。 然后,当您获得得分对象列表时,请在客户端按得分对它们进行排序,然后再按日期对关系进行排序。
  2. 根据日期为每个分数添加一个较小的值。该值必须足够小,这样才不会影响得分。例如:计算从纪元开始的分钟数(现在大约是25961)除以一百万,应该得到0.025961。将其添加到您的每个分数中不会改变分数排序,这将有助于确保它们按时间顺序排列。只是不要忘了在介绍分数时摆脱小数部分。