Bagaimana cara mendapatkan catatan N terakhir dengan activerecord?

163

Dengan :limitin query, saya akan mendapatkan N record pertama. Apa cara termudah untuk mendapatkan catatan N terakhir?

JtR
sumber

Jawaban:

143

Kueri rekaman aktif seperti ini menurut saya akan memberi Anda apa yang Anda inginkan ('Sesuatu' adalah nama model):

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

sunting : Seperti disebutkan dalam komentar, dengan cara lain:

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

while !result.empty?
        puts result.pop
end
Dan McNevin
sumber
tampaknya tidak perlu untuk memesan data dua kali, aku saat ini mendapatkan hitungan pertama dan menggunakannya dengan offset
JtR
Itu adalah metode lain yang saya pikirkan, tetapi sepertinya lebih banyak pekerjaan karena itu 2 pertanyaan terhadap database, bukan 1. Saya kira saya berasumsi bahwa Anda perlu beralih pada array di beberapa titik, sehingga Anda bisa membiarkan ruby ​​sort itu pada saat itu. (mis. records.reverse.each do ..)
Dan McNevin
Sebagai alternatif, Anda tidak dapat membalikkan array dan menggunakan Array.pop untuk beralih ke array daripada membalikkannya .. ruby-doc.org/core-1.8.7/classes/Array.html#M000280
Dan McNevin
1
Untuk Rails 3, lihat balasan Bongs sebagai gantinya. Cara ini masih berfungsi, tetapi bukan lagi cara yang disukai.
Kyle Heironimus
3
Memanggil #find (: semua) sudah usang. Panggil #all secara langsung saja.
Snowcrash
262

Ini adalah cara Rails 3

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

SomeModel.last(5).reverse # last 5 records in descending order
Bong
sumber
4
Coba ini dengan Postgres! Saya tentu memiliki masalah dengan pertama. Dalam SQL, pesanan tidak dijamin kecuali Anda menentukannya, tetapi MySQL lebih pemaaf.
Ghoti
5
Catatan: ini bukan cara yang baik untuk mengimplementasikannya, berdasarkan kinerja - setidaknya tidak hingga Rails 3.1. SomeModel.last (5) akan menjalankan pernyataan pilih tanpa batas, mengembalikan semua catatan SomeModel ke Ruby sebagai array, setelah itu Ruby akan memilih (5) elemen terakhir. Dari sisi efisiensi, saat ini, Anda ingin menggunakan batas - terutama jika Anda memiliki banyak elemen.
DRobinson
14
Itu tidak persis apa yang seharusnya:SELECT "items".* FROM "items" ORDER BY id DESC LIMIT 50
firedev
7
Di Rails 4 kueri yang dihasilkan oleh .last () juga optimal seperti yang disebutkan Nick
Jimmie Tyrrell
1
Ini tidak benar untuk Rails 4+, karena SomeModel.last(5).class== Array. Pendekatan yang benar adalah SomeModel.limit(5).order('id desc')per Arthur Neves, yang menghasilkanSELECT \"somemodels\".* FROM \"somemodels\" ORDER BY id desc LIMIT 5
Amin Ariana
50

cara baru untuk melakukannya di rel 3.1 adalah SomeModel.limit(5).order('id desc')

Arthur Neves
sumber
14
Ini lebih baik daripada last(5)karena mengembalikan ruang lingkup untuk rantai lebih lanjut.
lulalala
3
Saya menggunakan SomeModel.limit(100).reverse_orderRails 4 ( guides.rubyonrails.org/... ) Sama saja.
Ivan Black
Contoh "ruang lingkup untuk perangkaian lebih lanjut" yang disebutkan oleh @lulalala: Jika Anda hanya memerlukan satu kolom, SomeModel.limit(5).order('id desc').pluck(:col)akan melakukan SELECT SomeModel.col FROM SomeModel ORDER BY id desc LIMIT 5yang jauh lebih efisien daripada meraih semua kolom dan membuang semua kecuali satu kolom SomeModel.last(5).map(&:col) yang SELECT *bukan digunakan SELECT col(Anda tidak dapat memetik setelah memanggil terakhir; rantai lazy-eval berakhir dengan yang terakhir).
Kanat Bolazar
33

Untuk Rails 5 (dan kemungkinan Rails 4)

Buruk:

Something.last(5)

karena:

Something.last(5).class
=> Array

begitu:

Something.last(50000).count

kemungkinan akan meledakkan ingatan Anda atau mengambil selamanya.

Pendekatan yang baik:

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

karena:

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"

Yang terakhir adalah ruang lingkup yang tidak dievaluasi. Anda dapat mengaitkannya, atau mengonversinya menjadi array melalui .to_a. Begitu:

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

... butuh sedetik.

Amin Ariana
sumber
1
Dan bahkan Rails 3, sebenarnya. ;)
Joshua Pinter
32

Untuk versi Rails 4 dan di atasnya:

Anda dapat mencoba sesuatu seperti ini Jika Anda ingin entri tertua pertama

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

Anda dapat mencoba sesuatu seperti ini jika Anda ingin entri terbaru terakhir ..

YourModel.order(id: :desc).limit(5).each do |d|
Gagan Gami
sumber
1
Ini sepertinya lebih merupakan jawaban terkini untuk Rails 4 daripada yang diterima. Saya pikir sintaks terbaru akan terlihat seperti ini:YourModel.all.order(id: :desc).limit(5)
jmarceli
@ user2041318: terima kasih atas sintaks baru ini tanpa" "
Gagan Gami
2
Order () mengembalikan semua catatan. Tidak perlu rantai YourModel.all.order()karena sama denganYourModel.order()
Francisco Quintero
26

Solusi ada di sini:

SomeModel.last(5).reverse

Karena rails malas, pada akhirnya akan mengenai database dengan SQL seperti: "SELECT table. * FROM table ORDER BY table. idDESC LIMIT 5".

Pengembang
sumber
ini akan memuat semua catatanSomeModel
John Hinnegan
Pendekatan yang lebih baik adalah dengan membatasi (); ini tidak terlihat efisien.
Anurag
3
@ Pengembang benar sekali. SQL yang dieksekusi adalah: SELECT table .* FROM table` ORDER BY table. idDESC LIMIT 5` itu tidak melakukan pilih semua
ddavison
4

Jika Anda perlu mengatur pemesanan pada hasil kemudian gunakan:

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

jika Anda tidak memerlukan pemesanan apa pun, dan hanya perlu catatan disimpan di tabel kemudian gunakan:

Model.last(n) # n= any number
Thorin
sumber
4

Dalam (rails 4.2)proyek rel saya , saya gunakan

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

dan itu berhasil.

timlentse
sumber
3

kita bisa menggunakan Model.last(5)atau Model.limit(5).order(id: :desc)di rel 5.2

Joydeep Banerjee
sumber
2

Coba saja:

Model.order("field_for_sort desc").limit(5)
Thorin
sumber
2
Anda harus menjelaskan mengapa solusi ini layak.
Phiter
1

Saya menemukan bahwa kueri ini lebih baik / lebih cepat untuk menggunakan metode "pencabut", yang saya sukai:

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

Ini memberikan ActiveRecord sebagai output; jadi kamu bisa menggunakan .pluck di atasnya seperti ini:

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

yang dengan cepat memberikan id sebagai array saat menggunakan kode SQL yang optimal.

Brandon Meredith
sumber
Challenge.limit(5).order('id desc').idsakan bekerja dengan baik :)
Koen.
0

Jika Anda memiliki cakupan default dalam model Anda yang menentukan urutan naik di Rails 3 Anda harus menggunakan memesan ulang daripada memesan seperti yang ditentukan oleh Arthur Neves di atas:

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

atau

Something.reorder('id desc').limit(5)
scifisamurai
sumber
0

Katakanlah N = 5 dan model Anda adalah Message, Anda dapat melakukan sesuatu seperti ini:

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

Lihatlah sql:

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

Kuncinya adalah subselect. Pertama kita perlu mendefinisikan apa pesan terakhir yang kita inginkan dan kemudian kita harus memesannya dalam urutan menaik.

MatayoshiMariano
sumber
-4

Tambahkan parameter pesanan: ke kueri

frankodwyer
sumber