Як отримати останні N записів за допомогою активного запису?


163

З :limit запитом я отримаю перші N записів. Який найпростіший спосіб отримати останні N записів?

Відповіді:


143

Такий активний запит запису, як я думаю, отримав би те, що ви хочете ("Щось" - назва моделі):

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. Я думаю, я припускаю, що вам потрібно перебрати масив у якийсь момент, щоб ви могли дозволити сортувати рубін це на той час. (т. е. records.reverse.each do ..)
Ден МакНевін

Крім того, ви не можете змінити масив і використовувати Array.pop для ітерації над масивом, а не для його реверсування .. ruby-doc.org/core-1.8.7/classes/Array.html#M000280
Dan McNevin

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 прощає.
Ghoti

5
Зауважте: це не гарний спосіб його реалізації, залежно від продуктивності - принаймні, не до Rails 3.1. SomeModel.last (5) буде виконувати оператор select без обмеження, повертаючи всі записи SomeModel в Ruby як масив, після чого Ruby вибирає останні (5) елементів. В даний час ви хочете використовувати обмеження - особливо якщо у вас потенційно багато елементів.
DRobinson

14
Він робить саме те, що повинен:SELECT "items".* FROM "items" ORDER BY id DESC LIMIT 50
звільнений

7
У Rails 4 запит, згенерований .last (), також є оптимальним, як згадував Нік
Jimmie Tyrrell

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)тому, що це повертає простір для подальшого прив’язування.
lulalala

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

Для рейок 5 (та ймовірних рейок 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

Для версії 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: дякую за цей новий синтаксис без" "
Гаган Гамі

2
Order () повертає всі записи. Немає потреби ланцюгу, YourModel.all.order()оскільки це те саме, щоYourModel.order()
Франциско Кінтеро

26

Рішення тут:

SomeModel.last(5).reverse

Оскільки рейки ледачі, вони з часом потрапляють у базу даних із SQL на зразок: "SELECT table. * OF 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

і це працює.



2

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

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

2
Вам слід пояснити, чому таке рішення є життєздатним.
Фітер

1

Я вважаю, що цей запит краще / швидше для використання методу "pluck", який мені подобається:

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)

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

Ключ - це підбір. Спочатку нам потрібно визначити, які останні повідомлення ми хочемо, а потім нам їх потрібно замовити у порядку зростання.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.