在Firebase中分页大量数据的最有效方法

时间:2017-03-06 08:09:30

标签: ios firebase pagination firebase-realtime-database

我正在尝试为具有排名的帖子(类似于HackerNews)创建无限滚动,我想知道当存在大量数据时,使用Firebase分页/创建无限滚动的最有效方法是什么。

我一直在做的是我请求所有数据,对它们进行排序,然后限制滚动以创建无限滚动感。有没有办法创建这个无限滚动而不必请求所有数据然后对它们进行排序?

我用这种方法看到的问题是,如果我们有100K +条目,我们将不得不请求和排序100K +条目,这不会很好。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

由于排名是一个计算值,取决于自帖子创建以来的时间和帖子收到的分数,您实际上只有两个选项。您可以获取所有帖子并计算客户端的排名(在您的情况下不是一个选项),或者您可以在每次更新帖子时计算排名。另外,我在Swift中给出了我的例子。

此示例的DB结构:

posts : {
  $post: {
    stats : {
      score : scoreValue,
      ranking : rankingValue,
      createdAt : timestamp
    }
  }
}

具体而言,这意味着当创建新帖子时,您将为其分配默认分数并计算排名。

由于排名现在存储在数据库中,您可以使用

简单地获取前x个帖子
postsRef.queryOrdered(byChild:"stats/ranking").queryLimited(toLast: x)

或者

ref.queryOrdered(byChild: "stats/ranking").queryEnding(atValue: "lowestScoreSoFar").queryLimited(toLast: x)

现在,为了确保帖子的排名保持最新,您只需在更新分数的同一操作(交易)中更新排名。

ref.runTransactionBlock({ (currentData: FIRMutableData) ->   FIRTransactionResult in
  if var stats = currentData.value as? [String : Any] {
    var score = stats["score"] as? Int
    var createdAt = stats["createdAt"] as? Long
    score += 1
    var ranking = calculateRanking(score, createdAt)
    stats["score"] = score
    stats["ranking"] = ranking
    currentData.value = stats
    return FIRTransactionResult.success(withValue: currentData)
  }
  return FIRTransactionResult.success(withValue: currentData)
}) { (error, committed, snapshot) in
  if let error = error {
    print(error.localizedDescription)
  }
}

这种方法存在的问题是,如果没有人投票,那么得分较高的帖子将保持在最高位置。处理这个黑客新闻似乎是在他们的服务器上运行一个脚本,它每30秒更新一个随机帖子在顶部x的排名。您必须运行服务器并查看哪种设置最适合您的特定情况。

如果您使用类似于黑客新闻的算法,所有帖子的评分都将朝着0发展,您可以尝试随机更新排名高于某个阈值的帖子排名(这样您就会忽略较旧和不相关的帖子。)

Hacker News Algorithm

More info on the algorithm

How often does Hacker News recalculate rankings

How Hacker News algorithm really works