2011-07-25 57 views
0

我在數據庫中有一個模型。該模型具有感興趣3個按鍵:Rails 3 - 獲取最新記錄,具有獨特的未知值

created_at,類型,鍵

  • created_at,是,好了,時間戳
  • 類型是已知的枚舉。
  • 關鍵遵循一個約定,但通常是未知和非唯一的。

有潛在的數百個記錄與給定的類型和組合鍵,並且記錄可能不小。我試圖儘量避免從數據庫加載它們。

問題是有效地找到對象的最新版本(不必刪除舊版本)。我想從數據庫中爲每種類型的鍵獲取最新記錄,但我不知道鍵是什麼。查詢是我給了一個類型,我最終得到了一個哈希對象[key => object],其中我選擇的哈希對象是使用該鍵類型對的最新對象(最新的created_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

我會使用一個單獨的表,記錄在一個單獨的表中的最新記錄的ID,即。

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]的新記錄時,索引纔會更改。


編輯:有條件的逆轉