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


163

Con :limitin query, obtendré los primeros N registros. ¿Cuál es la forma más fácil de obtener los últimos N registros?

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

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

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')


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.


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|

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".


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

4

En mi (rails 4.2)proyecto de rieles , uso

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

y funciona.



2

Sólo inténtalo:

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

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.


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)

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.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.