Jak zdobyć ostatnie N rekordów z activerecord?


163

W :limitzapytaniu otrzymam pierwsze N ​​rekordów. Jaki jest najłatwiejszy sposób na zdobycie ostatnich N rekordów?

Odpowiedzi:


143

Wydaje mi się, że takie zapytanie dotyczące rekordu aktywnego dałoby ci to, czego chcesz („Coś” to nazwa modelu):

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

edycja : jak zauważono w komentarzach, inny sposób:

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

while !result.empty?
        puts result.pop
end

wydaje się zbędne zamawianie danych dwa razy, obecnie najpierw otrzymuję licznik i używam go z przesunięciem
JtR

To była inna metoda, o której myślałem, ale wydaje się, że jest to jeszcze więcej pracy, ponieważ są to 2 zapytania do bazy danych zamiast 1. Wydaje mi się, że w pewnym momencie musisz wykonać iterację po tablicy, więc możesz pozwolić na sortowanie ruby to w tamtym czasie. (tj. records.reverse.each do ..)
Dan McNevin

Alternatywnie, nie można odwrócić tablicy i użyć Array.pop do iteracji po tablicy zamiast jej odwracania. Ruby-doc.org/core-1.8.7/classes/Array.html#M000280
Dan

1
W przypadku Rails 3 zobacz zamiast tego odpowiedź Bonga. Ten sposób nadal działa, ale nie jest już preferowany.
Kyle Heironimus

3
Funkcja #find (: all) jest przestarzała. Zamiast tego zadzwoń bezpośrednio pod numer #all.
Snowcrash

262

To jest 3 sposób Railsów

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

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

4
Spróbuj tego z Postgres! Z pewnością miałem problem z pierwszym. W SQL kolejność nie jest gwarantowana, chyba że ją określisz, ale MySQL jest bardziej wyrozumiały.
Ghoti,

5
Uwaga: nie jest to dobry sposób na jego implementację, jeśli chodzi o wydajność - przynajmniej nie do Railsów 3.1. SomeModel.last (5) wykona instrukcję select bez ograniczeń, zwracając wszystkie rekordy SomeModel do Ruby jako tablicę, po czym Ruby wybierze ostatnie (5) elementy. Jeśli chodzi o wydajność, obecnie chcesz użyć limitu - szczególnie jeśli masz potencjalnie wiele elementów.
DRobinson,

14
Robi dokładnie to, co powinien:SELECT "items".* FROM "items" ORDER BY id DESC LIMIT 50
firedev

7
W Railsach 4 zapytanie generowane przez .last () jest również optymalne, jak wspomniał Nick
Jimmie Tyrrell.

1
Jest to niepoprawne dla Rails 4+, ponieważ SomeModel.last(5).class== Array. Prawidłowe podejście jest SomeModel.limit(5).order('id desc')według Arthura Nevesa, co skutkujeSELECT \"somemodels\".* FROM \"somemodels\" ORDER BY id desc LIMIT 5
Amin Ariana

50

nowym sposobem na zrobienie tego w railsach 3.1 jest SomeModel.limit(5).order('id desc')


14
Jest to lepsze niż last(5)to, że zwraca zakres do dalszego łączenia.
lulalala

3
Używam SomeModel.limit(100).reverse_orderna Rails 4 ( guide.rubyonrails.org/ ... ) To to samo.
Ivan Black

Przykład „zakresu dalszego łączenia w łańcuch” wspomniany przez @lulalala: Jeśli potrzebujesz tylko jednej kolumny, SomeModel.limit(5).order('id desc').pluck(:col)zrobi SELECT SomeModel.col FROM SomeModel ORDER BY id desc LIMIT 5to znacznie wydajniej niż przechwycenie wszystkich kolumn i odrzucenie wszystkich oprócz jednej kolumny, z SomeModel.last(5).map(&:col) którą robi SELECT *zamiast SELECT col(nie możesz wyciągnąć po wywołaniu last; łańcuch lazy-eval kończy się na last).
Kanat Bolazar

33

Dla Rails 5 (i prawdopodobnie Rails 4)

Zły:

Something.last(5)

ponieważ:

Something.last(5).class
=> Array

więc:

Something.last(50000).count

prawdopodobnie zniszczy twoją pamięć lub potrwa wieczność.

Dobre podejscie:

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

ponieważ:

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"

Ten ostatni jest niedocenianym zakresem. Możesz go połączyć w łańcuch lub przekonwertować na tablicę za pośrednictwem .to_a. Więc:

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

... zajmuje chwilę.


1
A właściwie nawet Rails 3. ;)
Joshua Pinter

32

Dla wersji Rails 4 i nowszych:

Możesz spróbować czegoś takiego, jeśli chcesz mieć pierwszy najstarszy wpis

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

Możesz spróbować czegoś takiego, jeśli chcesz mieć najnowsze wpisy .

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

1
Wygląda na to, że odpowiedź na Rails 4 jest bardziej aktualna niż zaakceptowana. Myślę, że najnowsza składnia powinna wyglądać następująco:YourModel.all.order(id: :desc).limit(5)
jmarceli

@ user2041318: dzięki za nową składnię bez" "
Gagan Gami

2
Order () zwraca wszystkie rekordy. Nie ma potrzeby łączenia się w łańcuch, YourModel.all.order()ponieważ jest tak samo jakYourModel.order()
Francisco Quintero,

26

Rozwiązanie jest tutaj:

SomeModel.last(5).reverse

Ponieważ railsy są leniwe, w końcu trafią do bazy danych z kodem SQL, takim jak: "SELECT table. * FROM table ORDER BY table. idDESC LIMIT 5".


to załadowałoby wszystkie rekordySomeModel
John Hinnegan

Lepszym podejściem byłoby ograniczenie (); to nie wygląda na wydajne.
Anurag

3
@Developer ma całkowitą rację. Wykonany SQL to: SELECT tabela .* FROM tabela` ORDER BY table. idDESC LIMIT 5` nie wykonuje wyboru wszystkiego
ddavison

4

Jeśli chcesz ustawić kolejność wyników, użyj:

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

jeśli nie potrzebujesz żadnego zamówienia, a potrzebujesz tylko rekordów zapisanych w tabeli, użyj:

Model.last(n) # n= any number

4

W moim (rails 4.2)projekcie szyn używam

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

i to działa.



2

Spróbuj:

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

2
Powinieneś wyjaśnić, dlaczego to rozwiązanie jest wykonalne.
Phiter

1

Uważam, że to zapytanie jest lepsze / szybsze przy używaniu metody „pluck”, którą uwielbiam:

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

Daje to ActiveRecord jako wyjście; więc możesz użyć .pluck na tym w ten sposób:

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

który szybko podaje identyfikatory jako tablicę przy użyciu optymalnego kodu SQL.


Challenge.limit(5).order('id desc').idsbędzie działać równie dobrze :)
Koen.

0

Jeśli masz domyślny zakres w swoim modelu, który określa kolejność rosnącą w Rails 3, będziesz musiał użyć zmiany kolejności zamiast kolejności określonej przez Arthura Nevesa powyżej:

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

lub

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

0

Powiedzmy, że N = 5, a Twój model to Message, możesz zrobić coś takiego:

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

Spójrz na sql:

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

Kluczem jest podselekcja. Najpierw musimy zdefiniować, jakie są ostatnie wiadomości, które chcemy, a następnie musimy uporządkować je w kolejności rosnącej.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.