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

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

问题描述

假设我正在使用Firebase作为评论系统,并且想要检索给定主题的评论,但是在一个主题中有太多评论,我不想一次性检索它们。我也希望最新的评论显示在上面。

看起来,以相反顺序显示Firebase记录的唯一方法是将其全部提取出来,然后反向对其进行迭代。



对于大型数据集,特别是对于移动客户端来说,这可能会很难实现。

更好的方法?什么是从Firebase查询分页数据的通用和首选解决方案,按升序或降序排列? strong>更新回答

@Tyler回答 stackoverflow.com/ a / 38024909/681290 是一个更新和更方便的答案这个问题

TL; DR



如果你想要做的是没有解决方案是:

$ $ p $ code> ref .orderBy(field,'DESC')。offset(n).limit(x)

在Firebase github中,有不受支持的工具进行分页,但仅限于升序。。
$ b 否则,这里是迄今为止我找到的最接近的解决方案。我故意将这个问题解释为通用的,而不仅仅是OP所要求的时间字段。




使用优先级我们的目标是使用 setWithPriority() setPriority() 问题:


  • 我没有看到使用索引的优先级字段的优势相反? (实际上,优先级存储为一个名为 .priority 的基础字段,您可以在导出json数据时看到)

  • 维护许多用例,确定设置的优先级值。




    具有负数据的冗余子字段

    例如,我们可以使用负时间戳 timeRev 索引字段除了时间以便能够最先获得最新的项目。

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

    问题:


    • 它增加了应用程序的复杂性:需要维护额外的字段
    • 可以打破字段的原子性(例如 score 字段可以一次更新,不知道是否有可能与两个字段,一个正面和一个负面)
    • 我认为这个解决方法是只有限制(),但是现在我们可以使用 limitToFist() limitToLast )和范围查询(见下面)


      $ b

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



      和多余的字段:

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

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



      由此产生的项目阵列只需在使用前倒转即可。 (只要记住 Array.prototype.reverse()是可变的,所以它会改变你的数组)




      • API文档说只有有序的键值可以设置为 startAt endAt 边界。如果大量项目共享相同的值,那么数据集不能以固定长度偏移量进行分割。


        以下项目的示例包含得分值:

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

        首页查询得到最好的得分项目:

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

        结果:

        pre $ $ b $ {
        d:{score:1},
        e:{score:2},
        f:{score:5}



        $ b $ p
        $ b

        注意,子集的第一项有一个 1 得分,所以我们通过选择得分 1 或更少的所有项目来尝试获得前一页面:

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

        使用该查询, code> b,c,d 项目,而不是根据API文档预期的 a,b,c 给定 endAt(1)是包含性的,所以它会尝试获得1的所有分数,并且无法对之前已经返回的排序进行排序。



        解决方法

        这可以通过不期望每个子集保持相同的记录量来缓解,并放弃那些已经被加载。

        但是,如果我的应用程序的第一百万用户有一个 0 得分,这个子集不能分页,因为 endAt 偏移量是无用的,因为它是基于记录数量



        我没有看到这个用例的任何解决方法,我猜Firebase不适用于这个: )

        编辑:最后,我使用 Algolia 为所有搜索相关的目的。这是一个非常好的API,我希望谷歌最终获得Algolia整合Firebase&阿尔戈利亚,因为它们的互补性接近100%!免责声明:不拥有股份! : - )


        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.

        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.

        Is there any better way? What is the generic and preferred solution to query paginated data from Firebase, in ascending or descending order?

        解决方案

        Updated answer

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

        TL;DR

        There is no solution if what you are looking to do is :

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

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

        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.


        Use priorities

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

        Issues :

        • 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

        Redundant child fields with negative data

        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);
        

        Issues :

        • 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)

        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.

        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)

        Issues :

        • 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.

        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)
        

        Results :

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

        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)
        

        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.

        Workaround

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

        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.

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

        Edit: 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天全站免登陆