如何在Active Record范围内返回给定记录ID后的N条记录?

时间:2014-09-01 23:22:25

标签: sql ruby-on-rails activerecord ruby-on-rails-4

给定有效记录scope,如何在给定记录后返回N条记录

例如,考虑我们有一个按人口排序的城市地区列表:

有效记录范围:

Area.ordered_by_population

返回的行:

ID | Area
------------
 9 | Tokyo
 2 | Jakarta
 7 | Seoul
 1 | Delhi
 8 | Shanghai
 4 | Manila
 3 | Karachi
 5 | New York City
 6 | São Paulo

现在我需要在ID 8(上海)之后返回3条下一条记录。结果将是:

4 | Manila
3 | Karachi
5 | New York City

rails调用将如下所示:

Area.ordered_by_population.records_after_id(id: 8, count: 3)

那么,我该如何编写这个records_after_id方法?

性能要求:该方法应该处理具有100K记录的数据库表并且速度相对较快(我在现代笔记本电脑上的目标是1ms)。

更新

Beerlington注意到这个问题的重要细微差别。不幸的是,我无法使用分页解决方案。我需要在给定记录后返回行。它必须相对于记录。

2 个答案:

答案 0 :(得分:2)

我可能误解了这个问题,但听起来你想要的是分页,而你实际上并不关心这个ID。我过去使用Kaminari gem成功了。只需更改查询中的limitoffset,您就可以在没有gem的情况下执行此操作,但gem使得管理更加用户友好。

与Kaminari:

Area.ordered_by_population.page(1).per(8)
Area.ordered_by_population.page(2).per(8)
Area.ordered_by_population.page(3).per(8)

没有Kaminari:

Area.ordered_by_population.limit(10).offset(0)
Area.ordered_by_population.limit(10).offset(10)
Area.ordered_by_population.limit(10).offset(20)

答案 1 :(得分:2)

records_after_id方法可以定义如下

    module Pager
      def records_after_id(id:, count:)
        relation = self.dup
        # perform the query and find the index of the id
        offset = relation.pluck(:id).find_index(id)
        # OFFSET LIMIT query starting +1 after the found id
        relation.offset(offset + 1).limit(count)
      end
    end

然后你可以按如下方式调用它

    Area.ordered_by_population.extending(Pager).records_after_id(id: 8, count: 3)

当返回Relation时,它可以被扩展,比如接下来3条记录的总和

    Area.ordered_by_population
    .extending(Pager)
    .records_after_id(id: 8, count: 3)
    .sum(:population)

http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-extending

的更多信息