Как получить последние N записей с помощью activerecord?

163

С помощью :limitзапроса я получу первые N записей. Какой самый простой способ получить последние N записей?

JtR
источник

Ответы:

143

Такой запрос активной записи, как я думаю, даст вам то, что вы хотите («Something» - название модели):

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

редактировать : как отмечено в комментариях, другой способ:

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

while !result.empty?
        puts result.pop
end
Дэн МакНевин
источник
кажется, нет необходимости заказывать данные дважды, в настоящее время я сначала получаю счет и использую его со смещением
JtR
Это был другой метод, о котором я думал, но это кажется еще большей работой, так как это 2 запроса к базе данных вместо 1. Я предполагаю, что в какой-то момент вам нужно перебрать массив, чтобы вы могли позволить сортировке ruby это в то время. (т. е. records.reverse.each do ..)
Дэн МакНевин
С другой стороны, вы не можете перевернуть массив и использовать Array.pop для перебора массива, а не для его реверсирования .. ruby-doc.org/core-1.8.7/classes/Array.html#M000280
Дэн МакНевин
1
Для Rails 3 см. Ответ Бонга. Этот способ все еще работает, но больше не является предпочтительным.
Кайл Хейронимус
3
Вызов #find (: all) устарел. Позвоните прямо #all.
Snowcrash
262

Это рельсы 3 пути

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

SomeModel.last(5).reverse # last 5 records in descending order
Бонги
источник
4
Попробуйте это с Postgres! У меня конечно были проблемы с первым. В SQL порядок не гарантируется, если вы его не укажете, но MySQL более щадящий.
Готи
5
Примечание: это не очень хороший способ реализации, с точки зрения производительности - по крайней мере, до Rails 3.1. SomeModel.last (5) выполнит оператор select без ограничения, вернув все записи SomeModel в Ruby в виде массива, после чего Ruby выберет последние (5) элементы. В плане эффективности в настоящее время вы хотите использовать ограничение - особенно если у вас потенциально много элементов.
DRobinson
14
Он делает именно то, что должен:SELECT "items".* FROM "items" ORDER BY id DESC LIMIT 50
firedev
7
В Rails 4 запрос, сгенерированный .last (), также является оптимальным, как упомянул Ник,
Джимми Тиррелл,
1
Это неверно для Rails 4+, так как SomeModel.last(5).class== Array. Правильный подход в SomeModel.limit(5).order('id desc')соответствии с Артуром Невесом, что приводит кSELECT \"somemodels\".* FROM \"somemodels\" ORDER BY id desc LIMIT 5
Амин Ариана
50

новый способ сделать это в рельсах 3.1 SomeModel.limit(5).order('id desc')

Артур Невес
источник
14
Это лучше, чем last(5)потому, что он возвращает область для дальнейшего создания цепочки.
Лулалала
3
Я использую SomeModel.limit(100).reverse_orderна Rails 4 ( guides.rubyonrails.org/… ) Это то же самое.
Иван Блэк
Пример «области видимости для дальнейшего объединения», упомянутый @lulalala: если вам нужен только один столбец, SomeModel.limit(5).order('id desc').pluck(:col)это SELECT SomeModel.col FROM SomeModel ORDER BY id desc LIMIT 5будет гораздо эффективнее, чем захват всех столбцов и отбрасывание всех столбцов, кроме одного, с SomeModel.last(5).map(&:col) которым SELECT *вместо SELECT col(вы не можете извлечь после вызова последний; лениво-цепочка заканчивается на последнюю).
Канат Болазар
33

Для Rails 5 (и, вероятно, Rails 4)

Плохой:

Something.last(5)

так как:

Something.last(5).class
=> Array

так:

Something.last(50000).count

вероятно, взорвет вашу память или навсегда.

Хороший подход:

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

так как:

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"

Последнее является неоцененной областью применения. Вы можете связать его или преобразовать в массив через .to_a. Так:

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

... занимает секунду.

Амин Ариана
источник
1
И даже Rails 3, на самом деле. ;)
Джошуа Пинтер
32

Для Rails 4 и выше:

Вы можете попробовать что-то вроде этого, если вы хотите первую самую старую запись

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

Вы можете попробовать что-то вроде этого, если вы хотите последние последние записи ..

YourModel.order(id: :desc).limit(5).each do |d|
Гаган Гами
источник
1
Это выглядит как более актуальный ответ для Rails 4, чем принятый. Я думаю, что самый последний синтаксис должен выглядеть следующим образом:YourModel.all.order(id: :desc).limit(5)
jmarceli
@ user2041318: спасибо за этот новый синтаксис без" "
Gagan Gami
2
Order () возвращает все записи. Там нет необходимости в цепи, YourModel.all.order()потому что это то же самое, чтоYourModel.order()
Франциско Кинтеро
26

Решение здесь:

SomeModel.last(5).reverse

Поскольку rails является ленивым, он в конечном итоге попадет в базу данных с помощью SQL, например: «SELECT table. * FROM table ORDER BY table. idDESC LIMIT 5».

разработчик
источник
это загрузит все записиSomeModel
Джон Хиннеган
Лучшим подходом было бы ограничение (); это не выглядит эффективным.
Анураг
3
@Developer абсолютно прав. Выполненный SQL был: SELECT таблица таблицы .* FROM ORDER BY table. idDESC LIMIT 5` не выполняет выделение всех
ddavison
4

Если вам нужно установить порядок следования результатов, используйте:

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

если вам не нужно упорядочивать, а просто нужно сохранять записи в таблице, используйте:

Model.last(n) # n= any number
Торин
источник
4

В моем (rails 4.2)проекте рельсов я использую

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

и это работает.

timlentse
источник
3

мы можем использовать Model.last(5)или Model.limit(5).order(id: :desc)в рельсах 5.2

Джойдип Банерджи
источник
2

Просто попробуй:

Model.order("field_for_sort desc").limit(5)
Торин
источник
2
Вы должны объяснить, почему это решение является жизнеспособным.
Phiter
1

Я считаю, что этот запрос лучше / быстрее для использования метода «срывать», который я люблю:

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

Это дает ActiveRecord в качестве вывода; так что вы можете использовать .pluck на нем так:

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

который быстро дает идентификаторы в виде массива при использовании оптимального кода SQL.

Брэндон Мередит
источник
Challenge.limit(5).order('id desc').idsбудет работать так же хорошо :)
Коен.
0

Если у вас есть область по умолчанию в вашей модели, которая задает восходящий порядок в Rails 3, вам нужно будет использовать переупорядочение, а не порядок, как указано Артуром Невесом выше:

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

или

Something.reorder('id desc').limit(5)
scifisamurai
источник
0

Допустим, N = 5 и ваша модель Message, вы можете сделать что-то вроде этого:

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

Посмотрите на sql:

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

Ключ - это отбор. Сначала нам нужно определить, какие последние сообщения мы хотим, а затем мы должны упорядочить их в порядке возрастания.

MatayoshiMariano
источник
-4

Добавьте параметр: order в запрос

frankodwyer
источник