Rails 3 - получить последнюю запись с уникальным неизвестным значением - PullRequest
0 голосов
/ 25 июля 2011

У меня есть модель в базе данных. Модель имеет 3 ключа интереса:

создал_, тип, ключ

  • создал_, это, ну, отметка времени
  • является известным перечислением.
  • ключ соответствует соглашению, но в целом он неизвестен и не уникален.

Возможно, существуют сотни записей с заданным типом и комбинацией клавиш, и записи могут быть не маленькими. Я стараюсь максимально не загружать их из базы данных.

Проблема состоит в том, чтобы эффективно найти последнюю версию объекта (без необходимости удалять старые версии). Я хочу получить последнюю запись из базы данных для каждого ключа типа, но я не знаю, что это за ключи. Запрос состоит в том, что я даю тип, и в итоге получаю хеш объектов [key => object], где объект, который я выбираю для хэша, - это самый новый объект (самое последнее значение create_at) с этой парой ключей.

Моей первой мыслью было сделать это в памяти

 # this is pseudo code, have not compiled
 models = Model.where(:type => :some_type).order("created_at desc")
 result = models.inject(Hash.new) {|r, m| r[m.key] = m unless r.has_key? m.key}

Но это станет ужасно большим, когда я масштабируюсь. Вторая мысль - получить все ключи, а затем запросить все модели. Что-то вроде:

 keys = Model.where(:type => :some_type).select("DISTINCT key").map{|m| m.key }
 result = keys.inject(Hash.new) {|r, k| r[k] = Model.where(:type => :some_type).where(:key => k).order("created_at").last; r }

Но, когда я пишу этот код, я просто продолжаю думать, должен быть лучший способ . Это решение помогло бы мне сделать много запросов к базе данных по мере роста. В какой-то момент мне все равно придется закрыть ключи, так что, если вы можете предложить решение, которое позволит мне ограничить / разбить на страницы результаты, еще лучше.

Итак, есть ли способ сделать это более эффективно? Может быть, магический поисковый параметр в Arel или ключевое слово в SQL, о котором я забыл?

1 Ответ

1 голос
/ 25 июля 2011

Я бы использовал отдельную таблицу, которая записывает идентификатор последней записи в отдельной таблице, т. Е.

class Model
  after_create :update_latest_record

  def update_latest_record
    if latest_model = LatestModelLookup.where(:type => self.type, :key => self.key)
      latest_model.update_attributes(:model_id => self.id)
    else
      LatestModelLookup.create(:type => self.type, :key => self.key, :model_id => self.id)
    end
  end
end

Вам понадобится индекс на LatestModelLookup(type, key) (и, вероятно, LatestModelLookup(type))

Поэтому, когда вам нужно запросить последние записи по ключу для типа, вам нужно будет сделать:

model_ids = LatestModelLookup.where(:type => type).select('model_id').map(&:model_id)
result = Model.find(model_ids).inject({}) { |res, rec| res[rec.key] = rec }

Преимущество наличия отдельной таблицы состоит в том, что накладные расходы на обновление индексов на LatestModelLookup довольно низки. Индексы изменятся только при добавлении новой записи для отдельного [type, key].


редактировать: условие было отменено

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...