2011-07-25 58 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]的新记录时,索引才会更改。


编辑:有条件的逆转