我有两个表,Users
和Responses
,每个用户有很多响应。我正在寻找对每个用户的响应集进行一些计算。类似下面的代码:
all_users = User.all
all_rs = Responses.all
all_users.map { |u| all_rs.where(user: u).count }
如上所述,这将为每个用户调用数据库。有没有办法预先缓存all_rs
数据,以便后续的每个where
都在内存中完成?
上面的逻辑可能很容易用sql编写,但想象一下map块中的代码包含了更多的工作。
答案 0 :(得分:1)
您需要的是计数器缓存(请参阅Rails Guide的第4.1.2.3节)。
要启用计数器缓存,首先,添加或更改迁移文件:
<强>分贝/迁移/ add_counter_cache_to_users.rb 强>
class AddCounterCacheToUsers < ActiveRecord::Migration
def change
# Counter cache field
add_column :users, :responses_count, :integer, null: false, default: 0
# Optionally add index to the column if you want to `order by` it.
add_index :users, :responses_cache
end
end
然后修改模型类
应用/模型/ response.rb 强>
class Response < ActiveRecord::Base
belongs_to :user, counter_cache: true
end
运行rake db:migrate
。从现在开始,每当创建Response
时,users.responses_count
列的值将自动递增1,每当Response
被销毁时,该列的值将减1。
如果您想要计算某人的回复,请拨打该用户的responses_count
。
user = User.first
user.responses_count #=> the responses count of the user
# or
user.responses.size
您的原始要求可以通过
来实现User.select(:responses_count).to_a
我想不出我怎么能错过这么简单的血腥解决方案
Response.group(:user_id).count
答案 1 :(得分:1)
您可以执行类似
的操作responses_by_user = Response.all.group_by(&:user_ud)
(假设Response具有user_id
属性)
然后,您可以执行responses_by_user[user.id]
以获取用户的响应,而无需进一步查询。请注意创建所有这些额外的ActiveRecord对象的开销。正如您所暗示的那样,您提供的非常具体的示例可以通过sql group / count来处理,这可能要快得多。
答案 2 :(得分:0)
这样的事可能吗?假设用户有很多回复
all_users = User.includes(:responses)
user_responses_count = all_users.map { |u| u.responses.count }
如果您有1000个用户,则不会查询响应1000次。如果这适用于您的用例,请告诉我。
请注意此查询级别缓存。不需要更改模型..