Подтвердить что ты не робот

Как получить последнюю запись из каждой группы в ActiveRecord?

В моем приложении Ruby on Rails у меня есть такая структура базы данных, как это:

Project.create(:group => "1", :date => "2014-01-01")
Project.create(:group => "1", :date => "2014-01-02")
Project.create(:group => "1", :date => "2014-01-03")

Project.create(:group => "2", :date => "2014-01-01")
Project.create(:group => "2", :date => "2014-01-02")
Project.create(:group => "2", :date => "2014-01-03")

# and so forth...

Как я могу получить последнюю запись из каждого group с помощью ActiveRecord?

Решение, вероятно, простое, но я не могу обойти это.

Спасибо за любую помощь.

4b9b3361

Ответ 1

Postgres

В Postgres это может быть достигнуто с помощью следующего запроса.

SELECT DISTINCT ON ("group") * FROM projects
ORDER BY "group", date DESC, id DESC

Поскольку столбец date может быть не уникальным здесь, я добавил дополнительное предложение ORDER BY на id DESC, чтобы разбить связь в пользу записи с более высоким идентификатором, в случае, если две записи в группе имеют такой же даты. Вместо этого вы можете использовать другой столбец, например, дату/время последнего обновления или так, что зависит от вашего варианта использования.

При переходе к ActiveRecord, к сожалению, нет API для DISTINCT ON, но мы все равно можем использовать простой SQL с select:

Project.select('DISTINCT ON ("group") *').order(:group, date: :desc, id: :desc)

или если вы предпочитаете использовать AREL вместо того, чтобы иметь сырой SQL:

p = Project.arel_table
Project.find_by_sql(
  p.project(p[Arel.star])
   .distinct_on(p[:group])
   .order(p[:group], p[:date].desc, p[:id].desc)
)

MySQL

Для других баз данных, таких как MySQL, это, к сожалению, не так удобно. Существует множество доступных решений, см., Например, этот ответ.

Ответ 2

Это работает для меня

ids = Message.select("MAX(id) AS id").group(:column_name).collect(&:id)
@result = Message.order("created_at DESC").where(:id => ids)

Ответ 3

Что-то вроде этого?

Project.select(:group).map(&:group).uniq.each do |grp|
  puts Project.where(group: grp).order("date DESC").last
end

Это будет проходить через все ваши группы и идентифицировать уникальные. В вашем примере он должен вернуть [ "1", "2" ]. Затем он выполняет итерацию по этому массиву и выбирает последний проект с идентификатором группы 1 и последним проектом с идентификатором группы 2.

** Обновление **

Просто понял, что вы сказали "последнее", а не "последнее", что потребовало добавления заказа для обеспечения последних работ. Последний по-прежнему тянет только один.

Ответ 4

Project.where(:group => "1", :date => "2014-01-01").last

.last - это то, что вы ищете.