Làm thế nào để có được N hồ sơ cuối cùng với Activerecord?


163

Với :limittruy vấn, tôi sẽ nhận được N bản ghi đầu tiên. Cách dễ nhất để có được hồ sơ N cuối cùng là gì?

Câu trả lời:


143

Một truy vấn bản ghi hoạt động như thế này tôi nghĩ sẽ mang lại cho bạn những gì bạn muốn ('Cái gì đó' là tên mô hình):

Something.find(:all, :order => "id desc", :limit => 5).reverse

chỉnh sửa : Như đã lưu ý trong các ý kiến, một cách khác:

result = Something.find(:all, :order => "id desc", :limit => 5)

while !result.empty?
        puts result.pop
end

dường như không cần thiết phải đặt hàng dữ liệu hai lần, hiện tại tôi đang đếm số đầu tiên và sử dụng dữ liệu đó với phần bù
JtR

Đó là phương pháp khác mà tôi đã nghĩ đến, nhưng có vẻ như còn nhiều công việc hơn vì đó là 2 truy vấn đối với cơ sở dữ liệu thay vì 1. Tôi đoán rằng tôi giả sử rằng bạn cần lặp lại qua mảng tại một số điểm, vì vậy bạn có thể để ruby ​​sắp xếp tại thời điểm đó (ví dụ: records.reverse.each do ..)
Dan McNevin

Thay phiên, bạn không thể đảo ngược mảng và sử dụng Array.pop để lặp lại mảng thay vì đảo ngược nó .. ruby-doc.org/core-1.8.7/groupes/Array.html#M000280
Dan McNevin

1
Đối với Rails 3, thay vào đó, hãy xem trả lời của Bongs. Cách này vẫn hoạt động, nhưng không còn là cách ưa thích.
Kyle Heironimus

3
Gọi #find (: tất cả) không được chấp nhận. Gọi #all trực tiếp thay thế.
Tuyết rơi

262

Đây là cách 3 đường ray

SomeModel.last(5) # last 5 records in ascending order

SomeModel.last(5).reverse # last 5 records in descending order

4
Hãy thử điều này với Postgres! Tôi chắc chắn đã gặp rắc rối với đầu tiên. Trong SQL, thứ tự không được đảm bảo trừ khi bạn chỉ định nó, nhưng MySQL thì dễ tha thứ hơn.
Ghoti

5
Lưu ý: đây không phải là một cách tốt để thực hiện nó, hiệu suất khôn ngoan - ít nhất là không lên đến Rails 3.1. Một sốModel.last (5) sẽ thực thi câu lệnh select mà không giới hạn, trả lại tất cả các bản ghi của someModel cho Ruby dưới dạng một mảng, sau đó Ruby sẽ chọn ra (5) phần tử cuối cùng. Hiệu quả, khôn ngoan, hiện tại, bạn muốn sử dụng giới hạn - đặc biệt nếu bạn có tiềm năng nhiều yếu tố.
DRobinson

14
Nó thực hiện chính xác những gì nó cần:SELECT "items".* FROM "items" ORDER BY id DESC LIMIT 50
fireev

7
Trong Rails 4, truy vấn được tạo bởi .last () cũng tối ưu như Nick đã đề cập
Jimmie Tyrrell

1
Điều này không chính xác cho Rails 4+, vì SomeModel.last(5).class== Array. Cách tiếp cận đúng là SomeModel.limit(5).order('id desc')theo Arthur Neves, kết quả làSELECT \"somemodels\".* FROM \"somemodels\" ORDER BY id desc LIMIT 5
Amin Ariana

50

cách mới để làm điều đó trong đường ray 3.1 là SomeModel.limit(5).order('id desc')


14
Điều này tốt hơn last(5)bởi vì nó trả về một phạm vi cho chuỗi tiếp theo.
lulalala

3
Tôi sử dụng SomeModel.limit(100).reverse_ordertrên Rails 4 ( guide.rubyonrails.org/ - ) Nó giống nhau.
Ivan Black

Ví dụ về "phạm vi cho chaining thêm" được đề cập bởi @lulalala: Nếu bạn chỉ cần một cột, SomeModel.limit(5).order('id desc').pluck(:col)sẽ làm SELECT SomeModel.col FROM SomeModel ORDER BY id desc LIMIT 5đó là hiệu quả hơn so với lấy tất cả các cột và loại bỏ tất cả nhưng một cột với SomeModel.last(5).map(&:col) mà không SELECT *thay vì SELECT col(bạn có thể không nhổ sau khi gọi cuối cùng, chuỗi lười biếng kết thúc với cuối cùng).
Kanat Bolazar

33

Đối với Rails 5 (và có thể Rails 4)

Xấu:

Something.last(5)

bởi vì:

Something.last(5).class
=> Array

vì thế:

Something.last(50000).count

sẽ có khả năng làm nổ tung bộ nhớ của bạn hoặc mất mãi mãi.

Cách tiếp cận tốt:

Something.limit(5).order('id desc')

bởi vì:

Something.limit(5).order('id desc').class
=> Image::ActiveRecord_Relation

Something.limit(5).order('id desc').to_sql
=> "SELECT  \"somethings\".* FROM \"somethings\" ORDER BY id desc LIMIT 5"

Cái sau là một phạm vi không được đánh giá. Bạn có thể xâu chuỗi nó, hoặc chuyển đổi nó thành một mảng thông qua .to_a. Vì thế:

Something.limit(50000).order('id desc').count

... Mất một giây.


1
Và thậm chí Rails 3, thực sự. ;)
Joshua Pinter

32

Đối với phiên bản Rails 4 trở lên:

Bạn có thể thử một cái gì đó như thế này Nếu bạn muốn mục cũ nhất đầu tiên

YourModel.order(id: :asc).limit(5).each do |d|

Bạn có thể thử một cái gì đó như thế này nếu bạn muốn các mục mới nhất ..

YourModel.order(id: :desc).limit(5).each do |d|

1
Điều này có vẻ như câu trả lời cập nhật hơn cho Rails 4 so với câu trả lời được chấp nhận. Tôi nghĩ rằng cú pháp gần đây nhất sẽ giống như thế này:YourModel.all.order(id: :desc).limit(5)
jmarceli

@ user2041318: cảm ơn vì cú pháp mới này mà không có" "
Gagan Gami

2
Đặt hàng () trả về tất cả các hồ sơ. Không cần phải xâu chuỗi YourModel.all.order()vì giống nhưYourModel.order()
Francisco Quintero

26

Giải pháp là đây:

SomeModel.last(5).reverse

Vì đường ray là lười biếng, cuối cùng nó sẽ tấn công cơ sở dữ liệu bằng SQL như: "CHỌN table. * TỪ table ĐẶT HÀNG B .NG table. idGIỚI HẠN MÔ TẢ 5".


điều này sẽ tải tất cả các hồ sơ củaSomeModel
John Hinnegan

Một cách tiếp cận tốt hơn sẽ là giới hạn (); Điều này có vẻ không hiệu quả.
Anurag

3
@ Nhà phát triển là hoàn toàn đúng. SQL được thực thi là: SELECT bảng .* FROM bảng` ĐẶT HÀNG B .NG table.idGIỚI HẠN DESC 5` nó không thực hiện chọn tất cả
ddavison

4

Nếu bạn cần đặt một số thứ tự trên kết quả thì sử dụng:

Model.order('name desc').limit(n) # n= number

nếu bạn không cần bất kỳ thứ tự nào và chỉ cần các bản ghi được lưu trong bảng thì hãy sử dụng:

Model.last(n) # n= any number

4

Trong (rails 4.2)dự án đường ray của tôi , tôi sử dụng

Model.last(10) # get the last 10 record order by id

Và nó hoạt động.


3

chúng ta có thể sử dụng Model.last(5)hoặc Model.limit(5).order(id: :desc)trong đường ray 5.2


2

Cứ thử đi:

Model.order("field_for_sort desc").limit(5)

2
Bạn nên giải thích tại sao giải pháp này là khả thi.
Phiter

1

Tôi thấy rằng truy vấn này tốt hơn / nhanh hơn khi sử dụng phương pháp "nhổ" mà tôi yêu thích:

Challenge.limit(5).order('id desc')

Điều này cung cấp cho ActiveRecord làm đầu ra; vì vậy bạn có thể sử dụng .pluck trên nó như thế này:

Challenge.limit(5).order('id desc').pluck(:id)

mà nhanh chóng cung cấp cho các id dưới dạng một mảng trong khi sử dụng mã SQL tối ưu.


Challenge.limit(5).order('id desc').idssẽ hoạt động tốt như vậy :)
Koen.

0

Nếu bạn có phạm vi mặc định trong mô hình của mình chỉ định thứ tự tăng dần trong Rails 3, bạn sẽ cần sử dụng sắp xếp lại thay vì đặt hàng theo quy định của Arthur Neves ở trên:

Something.limit(5).reorder('id desc')

hoặc là

Something.reorder('id desc').limit(5)

0

Giả sử N = 5 và mô hình của bạn là Message, bạn có thể làm một cái gì đó như thế này:

Message.order(id: :asc).from(Message.all.order(id: :desc).limit(5), :messages)

Nhìn vào sql:

SELECT "messages".* FROM (
  SELECT  "messages".* FROM "messages"  ORDER BY "messages"."created_at" DESC LIMIT 5
) messages  ORDER BY "messages"."created_at" ASC

Điều quan trọng là subselect. Đầu tiên chúng ta cần xác định những thông điệp cuối cùng chúng ta muốn là gì và sau đó chúng ta phải sắp xếp chúng theo thứ tự tăng dần.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.