Wie bekomme ich die letzten N Datensätze mit Activerecord?


163

Mit :limitin Abfrage bekomme ich erste N Datensätze. Was ist der einfachste Weg, um die letzten N Datensätze zu erhalten?

Antworten:


143

Eine aktive Datensatzabfrage wie diese würde Ihnen meiner Meinung nach das bringen, was Sie wollen ('Etwas' ist der Modellname):

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

bearbeiten : Wie in den Kommentaren erwähnt, eine andere Möglichkeit:

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

while !result.empty?
        puts result.pop
end

Es scheint unnötig, die Daten zweimal zu bestellen. Ich
erhalte

Das war die andere Methode, an die ich gedacht habe, aber das scheint noch mehr Arbeit zu sein, da dies 2 Abfragen für die Datenbank anstelle von 1 sind. Ich gehe davon aus, dass Sie irgendwann über das Array iterieren müssen, damit Sie Ruby sortieren können es zu dieser Zeit. (dh records.reverse.each do ..)
Dan McNevin

Alternativ können Sie das Array nicht umkehren und Array.pop verwenden, um über das Array zu iterieren, anstatt es umzukehren. Ruby-doc.org/core-1.8.7/classes/Array.html#M000280
Dan McNevin

1
Für Rails 3 siehe stattdessen die Antwort von Bongs. Dieser Weg funktioniert immer noch, ist aber nicht mehr der bevorzugte Weg.
Kyle Heironimus

3
Das Aufrufen von #find (: all) ist veraltet. Rufen Sie stattdessen #all direkt an.
Snowcrash

262

Dies ist der Rails 3-Weg

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

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

4
Versuchen Sie dies mit Postgres! Ich hatte sicherlich zuerst Probleme damit. In SQL kann die Reihenfolge nur garantiert werden, wenn Sie sie angeben. MySQL ist jedoch fehlerverzeihender.
Ghoti

5
Hinweis: Dies ist keine gute Möglichkeit, es in Bezug auf die Leistung zu implementieren - zumindest nicht bis zu Rails 3.1. SomeModel.last (5) führt die select-Anweisung unbegrenzt aus und gibt alle Datensätze von SomeModel als Array an Ruby zurück. Danach wählt Ruby die letzten (5) Elemente aus. In Bezug auf die Effizienz möchten Sie derzeit Limit verwenden - insbesondere, wenn Sie möglicherweise viele Elemente haben.
DRobinson

14
Es macht genau das, was es sollte:SELECT "items".* FROM "items" ORDER BY id DESC LIMIT 50
Firedev

7
In Rails 4 ist die von .last () generierte Abfrage auch optimal, wie Nick erwähnt hat
Jimmie Tyrrell

1
Dies ist für Rails 4+ falsch, da SomeModel.last(5).class== Array. Der richtige Ansatz ist SomeModel.limit(5).order('id desc')per Arthur Neves, was zuSELECT \"somemodels\".* FROM \"somemodels\" ORDER BY id desc LIMIT 5
Amin Ariana

50

Neue Möglichkeit, dies in Schienen 3.1 zu tun, ist SomeModel.limit(5).order('id desc')


14
Dies ist besser als last(5)weil es einen Spielraum für weitere Verkettung zurückgibt.
Lulalala

3
Ich benutze SomeModel.limit(100).reverse_orderauf Rails 4 ( guides.rubyonrails.org/… ) Es ist das gleiche.
Ivan Black

Beispiel für „Spielraum für eine weitere Verkettung“ von @lulalala erwähnt: Wenn Sie nur eine Spalte benötigen, SomeModel.limit(5).order('id desc').pluck(:col)tun wird , SELECT SomeModel.col FROM SomeModel ORDER BY id desc LIMIT 5was viel effizienter ist , alle Spalten als Grabbing und alle bis auf eine Spalte mit Verwerfen SomeModel.last(5).map(&:col) denen tut SELECT *statt SELECT col(nicht zupfen kann nach dem Aufruf last; faul-eval Kette endet mit last).
Kanat Bolazar

33

Für Schienen 5 (und wahrscheinlich Schienen 4)

Schlecht:

Something.last(5)

weil:

Something.last(5).class
=> Array

so:

Something.last(50000).count

wird wahrscheinlich dein Gedächtnis in die Luft jagen oder ewig dauern.

Guter Ansatz:

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

weil:

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"

Letzteres ist ein nicht bewerteter Bereich. Sie können es verketten oder über in ein Array konvertieren .to_a. So:

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

... dauert eine Sekunde.


1
Und sogar Rails 3. ;)
Joshua Pinter

32

Für Rails 4 und höher Version:

Sie können so etwas versuchen, wenn Sie den ersten ältesten Eintrag möchten

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

Sie können so etwas ausprobieren, wenn Sie die letzten Einträge wünschen .

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

1
Dies scheint eine aktuellere Antwort für Rails 4 zu sein als die akzeptierte. Ich denke, dass die neueste Syntax so aussehen sollte:YourModel.all.order(id: :desc).limit(5)
jmarceli

@ user2041318: Danke für diese neue Syntax ohne" "
Gagan Gami

2
Order () gibt alle Datensätze zurück. Es besteht keine Notwendigkeit zu verketten, YourModel.all.order()da es dasselbe ist wieYourModel.order()
Francisco Quintero

26

Lösung ist hier:

SomeModel.last(5).reverse

Da Rails faul ist, wird es schließlich mit SQL wie folgt in die Datenbank gelangen: "SELECT table. * FROM table ORDER BYtable . idDESC LIMIT 5".


Dies würde alle Aufzeichnungen vonSomeModel
John Hinnegan

Ein besserer Ansatz wäre es, () zu begrenzen; das sieht nicht effizient aus.
Anurag

3
@ Entwickler ist absolut richtig. Die ausgeführte SQL war: SELECT table .* FROM table` ORDER BY table. idDESC LIMIT 5` führt keine Auswahl aller aus
ddavison

4

Wenn Sie eine Reihenfolge für die Ergebnisse festlegen müssen, verwenden Sie:

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

Wenn Sie keine Bestellung benötigen und nur in der Tabelle gespeicherte Datensätze benötigen, verwenden Sie:

Model.last(n) # n= any number

4

In meinem Rails- (rails 4.2)Projekt verwende ich

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

und es funktioniert.



2

Probier's einfach:

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

2
Sie sollten erklären, warum diese Lösung praktikabel ist.
Phiter

1

Ich finde, dass diese Abfrage besser / schneller für die Verwendung der "Zupf" -Methode ist, die ich liebe:

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

Dies gibt einen ActiveRecord als Ausgabe; Sie können also .pluck wie folgt verwenden:

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

Dadurch werden die IDs schnell als Array angezeigt, während der optimale SQL-Code verwendet wird.


Challenge.limit(5).order('id desc').idswird genauso gut funktionieren :)
Koen.

0

Wenn Sie in Ihrem Modell einen Standardbereich haben, der eine aufsteigende Reihenfolge in Rails 3 angibt, müssen Sie die Neuordnung anstelle der von Arthur Neves oben angegebenen Reihenfolge verwenden:

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

oder

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

0

Angenommen, N = 5 und Ihr Modell lautet Message: Sie können Folgendes tun:

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

Schauen Sie sich die SQL an:

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

Der Schlüssel ist die Unterauswahl. Zuerst müssen wir definieren, was die letzten Nachrichten sind, die wir wollen, und dann müssen wir sie in aufsteigender Reihenfolge bestellen.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.