วิธีรับ N บันทึกล่าสุดด้วย activerecord


163

ด้วย:limitในการสอบถามผมจะได้รับการบันทึก N แรก วิธีที่ง่ายที่สุดในการรับ N ระเบียนล่าสุดคืออะไร

คำตอบ:


143

แบบสอบถามบันทึกการใช้งานเช่นนี้ฉันคิดว่าคุณจะได้รับสิ่งที่คุณต้องการ ('Something' คือชื่อรุ่น):

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

แก้ไข : ตามที่ระบุไว้ในความคิดเห็นอีกวิธีหนึ่ง:

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

while !result.empty?
        puts result.pop
end

ดูเหมือนว่าไม่จำเป็นที่จะสั่งซื้อข้อมูลสองครั้งฉันกำลังได้รับนับเป็นครั้งแรกและใช้กับการชดเชย
JTR

นั่นเป็นวิธีอื่นที่ฉันคิด แต่ดูเหมือนว่าจะทำงานได้มากขึ้นเนื่องจากเป็น 2 แบบสอบถามต่อฐานข้อมูลแทนที่จะเป็น 1 ฉันคิดว่าคุณต้องวนซ้ำแถวลำดับในบางจุดเพื่อให้คุณเรียงลำดับทับทิมได้ ในเวลานั้น (เช่น. records.reverse.each do .. )
Dan McNevin

อีกวิธีหนึ่งคุณไม่สามารถย้อนกลับอาร์เรย์และใช้ Array.pop เพื่อวนซ้ำอาร์เรย์ได้มากกว่าการย้อนกลับ .. ruby-doc.org/core-1.8.7/classes/Array.html#M000280
Dan McNevin

1
สำหรับ Rails 3 ดูการตอบกลับของ Bongs แทน วิธีนี้ยังใช้งานได้ แต่ไม่มีวิธีที่ต้องการอีกต่อไป
Kyle Heironimus

3
การโทร #find (: all) เลิกใช้แล้ว โทร #all โดยตรงแทน
Snowcrash

262

นี่คือ Rails 3 way

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

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

4
ลองสิ่งนี้กับ Postgres! ฉันมีปัญหากับครั้งแรก ใน SQL ใบสั่งจะไม่รับประกันถ้าคุณไม่ระบุ แต่ MySQL นั้นให้อภัยมากกว่า
Ghoti

5
หมายเหตุ: นี่ไม่ใช่วิธีที่ดีในการติดตั้งใช้งาน แต่อย่างน้อยก็ไม่ถึง Rails 3.1 SomeModel.last (5) จะดำเนินการคำสั่ง select โดยไม่มีข้อ จำกัด ส่งคืนระเบียนทั้งหมดของ SomeModel ไปยัง Ruby เป็นอาร์เรย์หลังจากนั้น Ruby จะเลือกองค์ประกอบ (5) สุดท้าย ในปัจจุบันคุณต้องการใช้ขีด จำกัด โดยเฉพาะอย่างยิ่งถ้าคุณมีองค์ประกอบหลายอย่าง
DRobinson

14
มันไม่ตรงกับสิ่งที่มันควรจะ:SELECT "items".* FROM "items" ORDER BY id DESC LIMIT 50
firedev

7
ใน Rails 4 เคียวรีที่สร้างโดย. last () ก็เหมาะสมที่สุดเมื่อพูดถึง Nick
Jimmie Tyrrell

1
นี้ไม่ถูกต้องสำหรับรถไฟ 4+ ตั้งแต่==SomeModel.last(5).class Arrayวิธีการที่ถูกต้องคือSomeModel.limit(5).order('id desc')ต่อ Arthur Neves ซึ่งส่งผลให้SELECT \"somemodels\".* FROM \"somemodels\" ORDER BY id desc LIMIT 5
Amin Ariana

50

วิธีใหม่ในการทำราง 3.1 คือ SomeModel.limit(5).order('id desc')


14
สิ่งนี้ดีกว่าlast(5)เพราะส่งคืนขอบเขตสำหรับการผูกมัดเพิ่มเติม
lulalala

3
ฉันใช้SomeModel.limit(100).reverse_orderกับ Rails 4 ( guide.rubyonrails.org/ ) เหมือนกัน
Ivan Black

ตัวอย่างของ "ขอบเขตสำหรับการผูกมัดเพิ่มเติม" ที่กล่าวถึงโดย @lulalala: หากคุณต้องการเพียงหนึ่งคอลัมน์SomeModel.limit(5).order('id desc').pluck(:col)จะทำสิ่งSELECT SomeModel.col FROM SomeModel ORDER BY id desc LIMIT 5ที่มีประสิทธิภาพมากกว่าการคว้าคอลัมน์ทั้งหมดและละทิ้งทั้งหมดยกเว้นคอลัมน์เดียวSomeModel.last(5).map(&:col) ซึ่งSELECT *แทนที่จะเป็นSELECT col(คุณไม่สามารถถอนได้หลังจากการโทร last; lazy-eval chain ลงท้ายด้วย last)
Kanat Bolazar

33

สำหรับ Rails 5 (และ Rails 4)

แย่:

Something.last(5)

เพราะ:

Something.last(5).class
=> Array

ดังนั้น:

Something.last(50000).count

จะทำให้ความทรงจำของคุณระเบิดหรือใช้เวลาตลอดไป

แนวทางที่ดี:

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

เพราะ:

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"

หลังเป็นขอบเขตที่ไม่ได้ประเมินค่า .to_aคุณสามารถโซ่หรือแปลงเป็นอาร์เรย์ผ่าน ดังนั้น:

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

... ใช้เวลาไม่กี่วินาที


1
และแม้กระทั่ง Rails 3 จริงๆ ;)
Joshua Pinter

32

สำหรับRails 4 และเวอร์ชั่นที่สูงกว่า:

คุณสามารถลองสิ่งนี้ถ้าคุณต้องการรายการแรกสุด

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

คุณสามารถลองสิ่งนี้ถ้าคุณต้องการรายการล่าสุด ..

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

1
ดูเหมือนจะเป็นคำตอบล่าสุดสำหรับ Rails 4 มากกว่าคำตอบที่ยอมรับแล้ว ฉันคิดว่าไวยากรณ์ล่าสุดควรมีลักษณะเช่นนี้:YourModel.all.order(id: :desc).limit(5)
jmarceli

@ user2041318: ขอบคุณสำหรับไวยากรณ์ใหม่นี้โดยไม่ต้อง" "
Gagan Gami

2
คำสั่งซื้อ () ส่งคืนระเบียนทั้งหมด ไม่จำเป็นต้องเชื่อมโยงYourModel.all.order()เพราะเป็นเช่นเดียวกับYourModel.order()
Francisco Quintero

26

โซลูชันอยู่ที่นี่:

SomeModel.last(5).reverse

ตั้งแต่รางเป็นคนขี้เกียจที่สุดก็จะตีฐานข้อมูลด้วย SQL ที่ชอบ: "SELECT table* FROM. table ORDER BY table. idDESC LIMIT 5"


สิ่งนี้จะโหลดบันทึกทั้งหมดของSomeModel
John Hinnegan

วิธีที่ดีกว่าคือการ จำกัด (); มันดูไม่มีประสิทธิภาพ
Anurag

3
@Developer ถูกต้องอย่างแน่นอน SQL ที่ดำเนินการคือ: SELECT ตาราง.* FROM table` ORDER tableBY idDESC LIMIT 5` มันไม่ได้ทำการเลือกทั้งหมด
ddavison

4

หากคุณต้องการตั้งค่าการเรียงลำดับผลลัพธ์ให้ใช้:

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

หากคุณไม่ต้องการสั่งซื้อใด ๆ และเพียงต้องการบันทึกที่บันทึกไว้ในตารางจากนั้นใช้:

Model.last(n) # n= any number

4

ใน(rails 4.2)โครงการรถไฟของฉันฉันใช้

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

และมันใช้งานได้



2

เพียงแค่พยายามที่:

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

2
คุณควรอธิบายว่าเพราะเหตุใดจึงแก้ปัญหานี้ได้
Phiter

1

ฉันพบว่าแบบสอบถามนี้ดีกว่า / เร็วกว่าสำหรับการใช้วิธี "ถอน" ซึ่งฉันชอบ:

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

สิ่งนี้จะให้ ActiveRecord เป็นผลลัพธ์ เพื่อให้คุณสามารถใช้. ดึงมันเช่นนี้:

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

ซึ่งให้รหัสเป็นอาร์เรย์ได้อย่างรวดเร็วในขณะที่ใช้รหัส SQL ที่ดีที่สุด


Challenge.limit(5).order('id desc').idsจะใช้งานได้เช่นกัน :)
Koen

0

หากคุณมีขอบเขตเริ่มต้นในแบบจำลองของคุณที่ระบุลำดับจากน้อยไปหามากใน Rails 3 คุณจะต้องใช้การจัดลำดับใหม่แทนการสั่งซื้อตามที่ระบุไว้โดย Arthur Neves ด้านบน:

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

หรือ

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

0

สมมุติว่า N = 5 และโมเดลของคุณคือMessageคุณสามารถทำสิ่งนี้:

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

ดู sql:

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

ที่สำคัญคือการเลือกย่อย ก่อนอื่นเราต้องกำหนดว่าอะไรคือข้อความสุดท้ายที่เราต้องการและจากนั้นเราต้องเรียงลำดับตามลำดับจากน้อยไปมาก


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.