如何在 Firebase 中按升序或降序检索分页的孩子? [英] How to retrieve paginated children in ascending or descending order in Firebase?

查看:20
本文介绍了如何在 Firebase 中按升序或降序检索分页的孩子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我将 firebase 用于评论系统,并且我想检索给定主题的评论,但是一个主题中有太多评论,我不想一次全部检索它们.我还希望将最新评论显示在顶部.

Suppose I'm using firebase for a commenting system and I want to retrieve the comments for a given topic, but there are so many comments in one topic that I don't want to retrieve them all at once. I also want the newest comments to be displayed on top.

似乎以相反的顺序显示 firebase 记录的唯一方法是检索它们,然后反向迭代它们.

It seems that the only way to display firebase records in reverse order is to retrieve them all and then iterate over them in reverse.

这在大型数据集上可能会变得非常笨拙,尤其是对于移动客户端.

This could get very unwieldy on large datasets, especially for mobile clients.

有没有更好的办法?从 Firebase 按升序或降序查询分页数据的通用和首选解决方案是什么?

推荐答案

更新答案

@Tyler answer stackoverflow.com/a/38024909/681290 是一个更及时、更方便的答案这个问题

@Tyler answer stackoverflow.com/a/38024909/681290 is a more up to date and more convenient answer for this question

TL;DR

如果您想做的是:

ref.orderBy(field, 'DESC').offset(n).limit(x)

此外,在 Firebase github 中有不受支持的工具 可以进行分页,尽管仅在 仅升序.

Also, in Firebase github there are unsupported tools that do pagination, although only in ascending order only.

否则,这里是我自己找到的最接近的可能解决方案,或者到目前为止在网络上.我故意将这个问题解释为一般性的,而不仅仅是 OP 询问的时间字段.

Otherwise, here are the closest possible solutions, that I have found myself, or on the web so far. I deliberately interpreted the question as generic, not only about time fields as asked by the OP.

使用优先级

目标是对子项使用 setWithPriority()setPriority() 以便以后能够使用 orderByPriority() 获取有序数据.

The goal is to use setWithPriority() and setPriority() on children to be able to get ordered data later with orderByPriority().

问题:

  • 我不认为使用索引的 priority 字段有什么优势?(实际上,priority存储在一个名为.priority的底层字段中,导出json数据时可以看到)
  • 许多用例难以维护,无法确定要设置的优先级值
  • I don't see the advantage over using an indexed priority field instead ? (in fact, priority is stored as an underlying field called .priority, that you can see when exporting json data)
  • Hard to maintain for many use cases, to determine value of priority to set

具有负数据的冗余子字段

例如,除了 time 之外,我们还可以使用负时间戳 timeRev 索引字段,以便能够首先获取最新的项目.

For example, we can use a negative timestamp timeRev indexed field in addition to time to be able to get the newest items first.

ref.orderByChild('timeRev')
   .limitToFirst(100);

问题:

  • 它增加了应用的复杂性:需要维护额外的字段
  • 可以打破字段的原子性(例如一个score字段可以一次更新,不确定是否可以使用两个字段,一个正一个负)
  • 我认为当 Firebase API 中只有 limit() 时使用了这种解决方法,但现在我们可以使用 limitToFist() 有点过时了>limitToLast() 和范围查询(见下文)
  • It adds more complexity to the app : additional fields need to be maintained
  • Can break atomicity of the field (for example a score field can be updated at once, not sure if it's possible with two fields, one positive and one negative)
  • I think this workaround was used when there was only limit() in the Firebase API, but is kinda obsolete now that we can use limitToFist(), limitToLast(), and range queries (see below)

使用 limitToLast() 和 endAt() 范围查询

Using limitToLast() and endAt() range queries

这让我们避免了负面和多余的字段:

This let us avoid negative and redundant field :

ref.orderBy('time')
   .limitToLast(100)

这对于时间戳字段应该非常有效,因为通常这是一个唯一字段.

This should be pretty effective with timestamp fields, because usually this is a unique field.

生成的项目数组只需在使用前反转即可.(记住 Array.prototype.reverse() 是可变的,所以它会改变你的数组)

The resulting array of items simply need to be reversed before use. (just remember Array.prototype.reverse() is mutable, so it will change your array)

问题:

  • API 文档说只能将有序键值设置为 startAtendAt 边界.如果许多项共享相同的值,则无法将数据集拆分为固定长度的偏移量.
  • The API docs say that only the ordered key value can be set as a startAt or endAt boundary. If a lot of items share the same value, the dataset cannot be split in fixed length offsets.

以下项目包含 score 值的示例:

Example with the following items holding a score value :

{
  items: {
    a: {score: 0},
    b: {score: 0},
    c: {score: 1},
    d: {score: 1},
    e: {score: 2},
    f: {score: 5}
  }
}

首页查询以获得最佳评分项目:

First page query to get the best scoring items :

ref.child('items').orderByChild('score')
   .limitToLast(3)

结果:

{
  d: {score: 1},
  e: {score: 2},
  f: {score: 5}
}

注意子集的第一项有 1 分数,因此我们尝试通过选择所有分数为 1 或更低的项目来获取上一页:

Note the first item of the subset has a 1 score, so we try to get the previous page by selecting all items with score of 1 or less :

ref.child('items').orderByChild('score')
   .endAt(1)
   .limitToLast(3)

通过该查询,我们得到 b,c,d 项,而不是 a,b,c 项,这是 API 文档所预期的,鉴于endAt(1) 是包含的,所以它会尝试得到所有的分数为 1,并且无法对之前已经返回的进行排序.

With that query, we get b,c,d items, instead of a,b,c items, which is expected as per the API docs, given the endAt(1) is inclusive, so it will try to get all scores of 1, and has no way to sort which were already returned before.

解决方法

这可以通过不期望每个子集保存相同数量的记录并丢弃那些已经加载的记录来缓解.

This can be mitigated by not expecting each subset to hold the same amount of record, and discarding those which have already been loaded.

但是,如果我的应用程序的前一百万用户有 0 分数,则该子集不能被分页,因为 endAt 偏移量是没用,因为它基于而不是记录数.

But, if the first million users of my app have a 0 score, this subset cannot be paginated, because the endAt offset is useless, as it is based on the value instead of the number of records.

我看不到此用例的任何解决方法,我猜 Firebase 不适合此用途:-)

I don't see any workaround for this use case, I guess Firebase is not intended for this :-)

最后,我将 Algolia 用于所有与搜索相关的目的.这是一个非常好的 API,我希望谷歌最终收购 Algolia 以集成 Firebase 和Algolia,因为它们的互补性接近 100%!免责声明:不拥有任何股份!!:-)

In the end, I am using Algolia for all search-related purpose. It's gt a really nice API, and I hope google ends up acquiring Algolia to integrate both Firebase & Algolia, as their complementarity is close to 100%! Disclaimer: no shares owned!! :-)

这篇关于如何在 Firebase 中按升序或降序检索分页的孩子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆