¿Cómo obtener los últimos N registros con activerecord?

Respuestas:

143

Creo que una consulta de registro activa como esta le daría lo que desea ('Algo' es el nombre del modelo):

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

editar : como se señaló en los comentarios, otra forma:

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

while !result.empty?
        puts result.pop
end
Dan McNevin
fuente
Parece innecesario ordenar los datos dos veces, actualmente estoy recibiendo el conteo primera y usarlo con el offset
JTR
Ese era el otro método en el que estaba pensando, pero parece aún más trabajo ya que son 2 consultas contra la base de datos en lugar de 1. Supongo que supongo que en algún momento debes iterar sobre la matriz, por lo que podrías dejar que Ruby se ordene en ese momento (es decir, records.reverse.each do ..)
Dan McNevin el
Alternativamente, no podría revertir la matriz y usar Array.pop para iterar sobre la matriz en lugar de revertirla. Ruby-doc.org/core-1.8.7/classes/Array.html#M000280
Dan McNevin
1
Para Rails 3, vea la respuesta de Bongs en su lugar. Esta manera todavía funciona, pero ya no es la forma preferida.
Kyle Heironimus
3
Llamar a #find (: all) está en desuso. Llame a #todos directamente en su lugar.
Snowcrash
262

Este es el camino de 3 carriles

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

SomeModel.last(5).reverse # last 5 records in descending order
Bongs
fuente
44
¡Prueba esto con Postgres! Ciertamente he tenido problemas con el primero. En SQL, el orden no está garantizado a menos que lo especifique, pero MySQL es más indulgente.
Ghoti
55
Nota: esta no es una buena forma de implementarlo, en términos de rendimiento, al menos no hasta Rails 3.1. SomeModel.last (5) ejecutará la instrucción select sin límite, devolviendo todos los registros de SomeModel a Ruby como una matriz, después de lo cual Ruby seleccionará los últimos (5) elementos. En términos de eficiencia, actualmente, desea utilizar el límite, especialmente si tiene potencialmente muchos elementos.
DRobinson
14
Hace exactamente lo que debe:SELECT "items".* FROM "items" ORDER BY id DESC LIMIT 50
firedev
77
En Rails 4, la consulta generada por .last () también es óptima como Nick mencionó
Jimmie Tyrrell el
1
Esto es incorrecto para Rails 4+, ya que SomeModel.last(5).class== Array. El enfoque correcto es SomeModel.limit(5).order('id desc')por Arthur Neves, lo que resulta enSELECT \"somemodels\".* FROM \"somemodels\" ORDER BY id desc LIMIT 5
Amin Ariana
50

nueva forma de hacerlo en rails 3.1 es SomeModel.limit(5).order('id desc')

Arthur Neves
fuente
14
Esto es mejor que last(5)porque devuelve un alcance para un mayor encadenamiento.
lulalala
3
Yo uso SomeModel.limit(100).reverse_orderen Rails 4 ( guides.rubyonrails.org/… ) Es lo mismo.
Ivan Black
Ejemplo de "alcance para un mayor encadenamiento" mencionado por @lulalala: si solo necesita una columna, SomeModel.limit(5).order('id desc').pluck(:col)lo hará SELECT SomeModel.col FROM SomeModel ORDER BY id desc LIMIT 5es mucho más eficiente que tomar todas las columnas y descartar todas las columnas, excepto una, con lo SomeModel.last(5).map(&:col) que hace en SELECT *lugar de SELECT col(no puede extraer después de llamar last; lazy-eval chain finaliza con last).
Kanat Bolazar
33

Para los rieles 5 (y probablemente los rieles 4)

Malo:

Something.last(5)

porque:

Something.last(5).class
=> Array

entonces:

Something.last(50000).count

probablemente explotará tu memoria o tardará una eternidad.

Buen enfoque:

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

porque:

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"

Este último es un alcance no evaluado. Puede encadenarlo o convertirlo en una matriz mediante .to_a. Entonces:

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

... toma un segundo.

Amin Ariana
fuente
1
E incluso Rails 3, en realidad. ;)
Joshua Pinter
32

Para Rails 4 y versiones superiores:

Puedes probar algo como esto si quieres la primera entrada más antigua

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

Puede probar algo como esto si desea las últimas últimas entradas .

YourModel.order(id: :desc).limit(5).each do |d|
Gagan Gami
fuente
1
Esto parece una respuesta más actualizada para Rails 4 que la aceptada. Creo que la sintaxis más reciente debería verse así:YourModel.all.order(id: :desc).limit(5)
jmarceli
@ user2041318: gracias por esta nueva sintaxis sin" "
Gagan Gami
2
Order () devuelve todos los registros. No hay necesidad de encadenar YourModel.all.order()porque es lo mismo queYourModel.order()
Francisco Quintero
26

La solución está aquí:

SomeModel.last(5).reverse

Como los rieles son perezosos, eventualmente llegará a la base de datos con SQL como: "SELECCIONAR table. * DESDE table ORDENAR POR table. idLÍMITE DESC 5".

Desarrollador
fuente
esto cargaría todos los registros deSomeModel
John Hinnegan
Un mejor enfoque sería limitar (); Esto no parece eficiente.
Anurag
3
@Developer tiene toda la razón. El SQL ejecutado fue: SELECT table .* FROM table` ORDER BY table. idDESC LIMIT 5` no realiza una selección de todo
ddavison
4

Si necesita establecer un orden en los resultados, use:

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

si no necesita ningún pedido y solo necesita guardar registros en la tabla, use:

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

En mi (rails 4.2)proyecto de rieles , uso

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

y funciona.

timlentse
fuente
3

podemos usar Model.last(5)o Model.limit(5).order(id: :desc)en rieles 5.2

Joydeep Banerjee
fuente
2

Sólo inténtalo:

Model.order("field_for_sort desc").limit(5)
Thorin
fuente
2
Debe explicar por qué esta solución es viable.
Phiter
1

Encuentro que esta consulta es mejor / más rápida para usar el método "pluck", que me encanta:

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

Esto le da un ActiveRecord como salida; para que pueda usar .pluck de esta manera:

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

que proporciona rápidamente los identificadores como una matriz mientras se utiliza un código SQL óptimo.

Brandon Meredith
fuente
Challenge.limit(5).order('id desc').idsfuncionará igual de bien :)
Koen.
0

Si tiene un alcance predeterminado en su modelo que especifica un orden ascendente en Rails 3, deberá usar el reordenamiento en lugar del orden especificado por Arthur Neves arriba:

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

o

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

Digamos N = 5 y su modelo es Message, puede hacer algo como esto:

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

Mira el sql:

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

La clave es la subselección. Primero necesitamos definir cuáles son los últimos mensajes que queremos y luego tenemos que ordenarlos en orden ascendente.

MatayoshiMariano
fuente
-4

Agregue un parámetro de orden a la consulta

frankodwyer
fuente