简体   繁体   English

Rails:“缓存”关联模型值的平均值

[英]Rails: “Caching” the average of an associated model's values

In Rails, I have some models that look like this: 在Rails中,我有一些看起来像这样的模型:

class Product
  has_many :listings
end

class Listing
  belongs_to :product
  # quantity_in_kg
  # total_price
  # price_per_kg = total_price / quantity_in_kg
end

I'd like to be able to compare the listings for a product based on the price per kilogram, compared to the price per kilogram for the product. 我希望能够根据产品的每公斤价格与产品的每公斤价格进行比较。 For example, this listing is only $2 per kilogram, whereas the product's average is $3. 例如,此清单的价格仅为每公斤2美元,而产品的平均价格为3美元。

Eventually, I'd like to be able to run a query that says "give me all of the listings which are below the average price of their product". 最终,我希望能够运行一个查询,说“给我所有低于其产品平均价格的商品”。

What's an effective way of doing this? 有效的方法是什么? I was thinking of something custom with ActiveRecord callbacks, and caching the per-kilo average in the products table, and the per-kilo price for each listing in the listings table. 我正在考虑使用ActiveRecord回调进行自定义,并在products表中缓存每千平均价格,并在listings表中缓存每个列表的每千价格。 There's probably a lot of scope for getting that wrong, so I was wondering if there was another way. 可能有很多问题可以解决,所以我想知道是否还有另一种方法。

I'm using Postgres 9.6 and Rails 5.1.0. 我正在使用Postgres 9.6和Rails 5.1.0。

(Bonus points: listings can also be active/inactive, and I'd only like to compare the average of all active listings). (加分点:列表也可以是活跃/不活跃的,我只想比较所有活跃列表的平均值)。

My suggestion is to start with a simple after_save callback and see where it takes you. 我的建议是从一个简单的after_save回调开始,看看它将带您到哪里。 You can add some updating criteria like "only recalculate on create/destroy or if active has been updated", add some transactions if you're feeling extra careful, etc.. 您可以添加一些更新条件,例如“仅在创建/销毁时重新计算,或者如果active已被更新”,如果您格外小心,则添加一些事务等。

If gets too slow, add a background worker to update it regularly (for example). 如果太慢,请添加后台工作人员定期进行更新(例如)。

class Listing
  after_save do
    product.update(
      avg_price_per_kg: product.listings.where(active: true).average(:price_per_kg)
    )
  end
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM