Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
482 views
in Technique[技术] by (71.8m points)

ruby each loop in order on sql order query result

I have a query in my Controller that works perfectly:

@klasses_mon = Klass.order(:start).where(day: 'MON').find_each

my result is (shown by <%= @klasses_mon.inspect %> in my view):

#<Enumerator: #<ActiveRecord::Relation 
[#<Klass id: 9, name: "Cycling", teacher: "Tomek", day: "MON", start: 510, duration: 45>,
#<Klass id: 8, name: "LBT", teacher: "Monia", day: "MON", start: 600, duration: 60>, 
#<Klass id: 11, name: "HIIT", teacher: "Aga", day: "MON", start: 930, duration: 45>]>
:find_each({:start=>nil, :finish=>nil, :batch_size=>1000, :error_on_ignore=>nil})>

But I am trying to display it in each loop. For some reason it is not ordered anymore. Looks like each loop does not keep the order from my query result:

<% @klasses_mon.each do |k| %>
    <p><%= k.teacher %>,
    <%= k.name %>
    START: <%= k.start/60 %>:<%= k.start%60 %>
<% end %>

result:

Monia, LBT START: 10:0

Tomek, Cycling START: 8:30

Aga, HIIT START: 15:30

How should I do that?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

From the fine manual:

find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
[...]
NOTE: It's not possible to set the order. That is automatically set to ascending on the primary key (“id ASC”) to make the batch ordering work. This also means that this method only works when the primary key is orderable (e.g. an integer or string).

So find_each is explicitly documented to ignore any ordering that you try to use.

find_each doesn't use LIMIT and OFFSET to move the batch window through the result set as that tends to be very expensive as the OFFSET increases, instead it orders by the primary key and includes a id > last_one condition in the WHERE clause to set the start of the batch and a LIMIT clause to set the batch size. Ordering by the PK and querying on the PK are both generally inexpensive as is a LIMIT clause.

find_each is the wrong tool for this job, find_each is for batch work but you're just displaying a short list of records so you want a simple:

@klasses_mon = Klass.order(:start).where(day: 'MON')

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...