楷模:
- 用户 has_many 类别,has_many 条目
- 类别 has_many 条目
- 条目属于类别和用户
让我们假设,条目上有一个名称和一个数量。如果我有一个视图需要为特定用户显示特定月份(现在让我们以 created_at 为例),并希望显示一个表格,其中包含按类别分组的特定月份中的所有条目(不显示空类别)和总和和类别中的条目数。
我的问题是:查询数据库(并充分利用缓存)的最有效方法是什么?此视图将经常呈现,并且每次用户创建新条目时,自然会更改一个类别的总和,但不会更改其他类别的总和。
楷模:
让我们假设,条目上有一个名称和一个数量。如果我有一个视图需要为特定用户显示特定月份(现在让我们以 created_at 为例),并希望显示一个表格,其中包含按类别分组的特定月份中的所有条目(不显示空类别)和总和和类别中的条目数。
我的问题是:查询数据库(并充分利用缓存)的最有效方法是什么?此视图将经常呈现,并且每次用户创建新条目时,自然会更改一个类别的总和,但不会更改其他类别的总和。
查询部分可以通过范围非常简单地完成:
class Category
scope :grouped_entries, lambda { |user, date|
select(['categories.*', 'COUNT(entries.id) as count_entries'])
.joins(:entries)
.where('entries.user_id = ?', user.id)
.where('MONTH(entries.created_at) = ?', date.month)
.group('categories.id')
}
end
然后可以循环:
<% Category.grouped_entries(current_user, Date.today).each do |category| %>
<%= category.name %> with <%= category.count_entries %> entries this month.
<% end %>
当然,缓存这需要您在本月创建条目时刷新缓存。例如,您可以像这样缓存查询:
@categories = Rails.cache.fetch("/grouped_entries/#{current_user.id}/#{Date.today.month}") do
Category.grouped_entries(current_user, Date.today).all
end
然后在使用 user_id 和条目 created_at 月份创建新条目时简单地将其过期。我想说您应该先使用这种方法,然后再尝试单独缓存每个类别的条目。此查询应该执行得很快,因此您不必深入研究单独缓存每一行。它还将执行单个查询,而不是为每个类别执行一个查询。
这就是为什么我不会单独缓存每一行的原因:
潘的回答很完美,帮助很大。对于档案:这是我在我的应用程序中使用的查询:
scope :grouped_entries, lambda { |user, date|
select(['categories.*', 'COUNT(entries.id) as count_entries']).
joins(:entries).
where('entries.user_id = ?', user.id).
where(':first_day <= entries.created_at AND entries.created_at <= :last_day', {
:first_day => date.at_beginning_of_month,
:last_day => date.at_end_of_month
} ).
group('categories.id')
}