Come ottenere gli ultimi N record con activerecord?


163

Con :limitin query, otterrò i primi N record. Qual è il modo più semplice per ottenere gli ultimi N record?

Risposte:


143

Una query di record attiva come questa penso che ti procurerebbe quello che vuoi ("Something" è il nome del modello):

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

modifica : come notato nei commenti, un altro modo:

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

while !result.empty?
        puts result.pop
end

sembra inutile ordinare i dati due volte, attualmente sto ricevendo prima il conteggio e lo sto usando con offset
JtR

Quello era l'altro metodo a cui stavo pensando, ma sembra che funzioni ancora di più dato che ci sono 2 query sul database invece di 1. Immagino che a un certo punto sia necessario eseguire l'iterazione sull'array, in modo da poter consentire a Ruby di ordinare in quel momento. (es. records.reverse.each do ..)
Dan McNevin

In alternativa, non è possibile invertire l'array e utilizzare Array.pop per scorrere sull'array anziché invertirlo. Ruby-doc.org/core-1.8.7/classes/Array.html#M000280
Dan McNevin

1
Per Rails 3, vedi invece la risposta di Bong. In questo modo funziona ancora, ma non è più il modo preferito.
Kyle Heironimus,

3
Chiamare #find (: all) è deprecato. Chiama invece direttamente #all.
Snowcrash,

262

Questo è il modo di Rails 3

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

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

4
Prova questo con Postgres! Ho sicuramente avuto problemi con il primo. In SQL l'ordine non è garantito se non specificato, ma MySQL è più indulgente.
Ghoti,

5
Nota: questo non è un buon modo per implementarlo, dal punto di vista delle prestazioni - almeno non fino a Rails 3.1. SomeModel.last (5) eseguirà l'istruzione select senza limiti, restituendo tutti i record di SomeModel a Ruby come un array, dopo di che Ruby sceglierà gli ultimi (5) elementi. Dal punto di vista dell'efficienza, al momento, si desidera utilizzare il limite, in particolare se si hanno potenzialmente molti elementi.
DRobinson,

14
Fa esattamente quello che dovrebbe:SELECT "items".* FROM "items" ORDER BY id DESC LIMIT 50
firedev

7
In Rails 4 anche la query generata da .last () è ottimale, come menzionato da Nick
Jimmie Tyrrell,

1
Questo non è corretto per Rails 4+, poiché SomeModel.last(5).class== Array. L'approccio corretto è SomeModel.limit(5).order('id desc')per Arthur Neves, che si traduce inSELECT \"somemodels\".* FROM \"somemodels\" ORDER BY id desc LIMIT 5
Amin Ariana,

50

è il nuovo modo di farlo su binari 3.1 SomeModel.limit(5).order('id desc')


14
Questo è meglio che last(5)perché restituisce un margine per un ulteriore concatenamento.
Lulalala,

3
Uso SomeModel.limit(100).reverse_ordersu Rails 4 ( guide.rubyonrails.org/… ) È lo stesso.
Ivan Black

Esempio di "ambito per ulteriori concatenamenti" menzionato da @lulalala: se hai bisogno solo di una colonna, SomeModel.limit(5).order('id desc').pluck(:col)farà ciò SELECT SomeModel.col FROM SomeModel ORDER BY id desc LIMIT 5che è molto più efficiente che afferrare tutte le colonne e scartare tutte le colonne tranne una con SomeModel.last(5).map(&:col) cui SELECT *invece di SELECT col(non puoi pizzicare dopo aver chiamato ultimo; la catena pigro-eval termina con l'ultimo).
Kanat Bolazar,

33

Per Rails 5 (e probabilmente Rails 4)

Male:

Something.last(5)

perché:

Something.last(5).class
=> Array

così:

Something.last(50000).count

probabilmente farà esplodere la tua memoria o impiegherà un'eternità.

Buon approccio:

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

perché:

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"

Quest'ultimo è un ambito non valutato. È possibile concatenarlo o convertirlo in un array tramite .to_a. Così:

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

... ci vuole un secondo.


1
E persino Rails 3, in realtà. ;)
Joshua Pinter

32

Per Rails 4 e versioni successive:

Puoi provare qualcosa del genere Se vuoi la prima voce più vecchia

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

Puoi provare qualcosa del genere se vuoi le ultime ultime voci ..

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

1
Questa sembra una risposta più aggiornata per Rails 4 rispetto a quella accettata. Penso che la sintassi più recente dovrebbe apparire così:YourModel.all.order(id: :desc).limit(5)
jmarceli,

@utente2041318: grazie per questa nuova sintassi senza" "
Gagan Gami

2
Ordine () restituisce tutti i record. Non è necessario concatenarsi YourModel.all.order()perché è lo stesso diYourModel.order()
Francisco Quintero,

26

La soluzione è qui:

SomeModel.last(5).reverse

Poiché le rotaie sono pigre, alla fine colpiranno il database con SQL come: "SELECT table. * FROM table ORDER BY table. idDESC LIMIT 5".


questo caricherà tutti i record diSomeModel
John Hinnegan il

Un approccio migliore sarebbe limitare (); questo non sembra efficiente.
Anurag,

3
@Developer ha assolutamente ragione. L'SQL eseguito era: SELECT tabella .* FROM tabella` ORDER BY table. idDESC LIMIT 5` non esegue un seleziona tutto
ddavison

4

Se è necessario impostare alcuni ordini sui risultati, utilizzare:

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

se non hai bisogno di alcun ordine e hai solo bisogno di salvare i record nella tabella, allora usa:

Model.last(n) # n= any number

4

Nel mio (rails 4.2)progetto di rotaie , utilizzo

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

e funziona.



2

Prova:

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

2
Dovresti spiegare perché questa soluzione è praticabile.
Phiter,

1

Trovo che questa query sia migliore / più veloce per l'utilizzo del metodo "pluck", che adoro:

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

Ciò fornisce un ActiveRecord come output; quindi puoi usare .pluck su di esso in questo modo:

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

che fornisce rapidamente gli ID come array durante l'utilizzo del codice SQL ottimale.


Challenge.limit(5).order('id desc').idsfunzionerà altrettanto bene :)
Koen.

0

Se nel tuo modello hai un ambito predefinito che specifica un ordine crescente in Rails 3 dovrai utilizzare il riordino anziché l'ordine come specificato da Arthur Neves sopra:

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

o

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

0

Diciamo N = 5 e il tuo modello è Message, puoi fare qualcosa del genere:

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

Guarda sql:

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

La chiave è la sottoselezione. Prima di tutto dobbiamo definire quali sono gli ultimi messaggi che vogliamo e poi dobbiamo ordinarli in ordine crescente.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.