Rails: итерация по всем объектам типа без загрузки их сразу
class Car << ActiveRecord::Base
end
Car.all.each do |car|
# do stuff
end
Это загружает все объекты типа Car в память (я думаю) и повторяется через них. Вместо этого я хочу перебрать все идентификаторы и загрузить их по одному так:
Car.all_ids.each do |id|
c = Car.find id
# do stuff
end
Но all_ids не существует, есть ли эквивалент?
Ответы
Ответ 1
Вы можете сделать следующее:
Car.find(:all, :select => :id).each do |car_id|
c = Car.find(car_id.id)
end
для Rails 2.3, не знакомый с 3 еще
Edit
Одним из возможных решений является более эффективное (меньше запросов):
Car.find(:all, :select => :id).map(&:id).each_slice(5) do |ids|
cars_slice = Car.find(ids)
end
Ответ 2
Для Rails 2.3 и выше (включая Rails 3) самым простым решением является find_each:
Car.find_each do |car|
# do stuff
end
Выполняет запрос автоматически, автоматически. Размер партии по умолчанию - 1000, но вы можете установить свой собственный. Он также работает вместе с названными областями и ActiveRecord:: Relations:
Car.hotrods.where(:color => 'red').find_each(:batch_size => 10) { do |car| ... }
См. http://guides.rubyonrails.org/active_record_querying.html#retrieving-multiple-objects-in-batches
Ответ 3
Вы можете использовать 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
Ответ 4
В Rails 4+ я нахожу pluck очень полезным.
Car.pluck(:id).each do |id|
c = Car.find id
# do stuff
end
Car.pluck(:id)
возвращает массив записей. Вы можете вырезать любой другой столбец вашей модели, изменив параметр. Кроме того, вы можете вырвать комбинацию столбцов. Например:
Car.pluck(:id, :make, :model).each do |id, make, model|
c = Car.find id
# access make and model as well
end