Rails:迭代一个类型的所有对象,而不是一次加载它们

Ste*_*son 21 ruby-on-rails

class Car << ActiveRecord::Base
end

Car.all.each do |car|
  # do stuff
end
Run Code Online (Sandbox Code Playgroud)

这会将Car类型的所有对象加载到内存中(我认为)并遍历它们.我想要的是迭代所有id并一次加载一个,如下所示:

Car.all_ids.each do |id|
  c = Car.find id
  # do stuff
end
Run Code Online (Sandbox Code Playgroud)

但是all_ids不存在,是否存在等价物?

nau*_*ter 56

对于Rails 2.3及更高版本(包括Rails 3),最简单的解决方案是find_each:

Car.find_each do |car|
  # do stuff
end
Run Code Online (Sandbox Code Playgroud)

这会自动为您执行批量查询.默认批处理大小为1000,但您可以设置自己的批处理大小.它还与命名范围和ActiveRecord :: Relations一起使用:

Car.hotrods.where(:color => 'red').find_each(:batch_size => 10) { do |car| ... }
Run Code Online (Sandbox Code Playgroud)

http://guides.rubyonrails.org/active_record_querying.html#retrieving-multiple-objects-in-batches

  • 精彩.不敢相信我不知道这件事. (2认同)

rye*_*guy 13

您可以使用find_in_batches,它一次获取记录x,其中x可配置,默认为1000.

  Person.where("age > 21").find_in_batches do |group|
    # group is an array of 1000 records
    group.each { |person| person.party_all_night! }
  end
Run Code Online (Sandbox Code Playgroud)


acw*_*acw 6

您可以执行以下操作:


Car.find(:all, :select => :id).each do |car_id|
  c = Car.find(car_id.id)
end
Run Code Online (Sandbox Code Playgroud)

对于Rails 2.3,还不熟悉3

编辑:

一种可能的解决方案是提高效率(减少查询):


Car.find(:all, :select => :id).map(&:id).each_slice(5) do |ids|
  cars_slice = Car.find(ids)
end
Run Code Online (Sandbox Code Playgroud)


Epi*_*ene 5

在 Rails 4+ 中,我发现pluck非常有用。

Car.pluck(:id).each do |id|
  c = Car.find id
  # do stuff
end
Run Code Online (Sandbox Code Playgroud)

Car.pluck(:id)返回一个条目数组。您可以通过更改参数来提取模型的任何其他列。此外,您可以选取列的组合。例如:

Car.pluck(:id, :make, :model).each do |id, make, model|
  c = Car.find id
  # access make and model as well
end
Run Code Online (Sandbox Code Playgroud)