考虑这个模型:
User:
id: int
Valuable:
id: int
user_id: int
value: int
用户有很多贵重物品。
现在就是这样。我想使用ActiveRecord选择任何查询的多个用户,之后我希望能够看到所有贵重物品的总和,,而不必进行N + 1次查询。
所以,我希望能够做到这一点:
# @var ids [Array] A bunch of User IDs.
User.where(id: ids).each do |u|
puts "User ##{u.id} has total value of #{u.total_value}
end
它应该执行1(或最多2)个查询,而不是实例化所有贵重物品。我试过玩select('*, SUM(valuables.value) as total_value).joins(valuables)
,但没有运气。我正在使用PostgreSQL
如果可能的话,我希望这会自动发生(例如使用default_scope
),我仍然希望能够使用includes
。
更新:抱歉,我还不清楚这一点。 (实际上,我确实写过)。我不希望实例化所有贵重物品。我想让PostgreSQL为我做计算。
UPDATE:我的意思是,我想依赖PostgreSQL的SUM方法来获得结果集中的总和。我认为我使用SELECT
和GROUP BY
的努力清楚了。我不希望Valuables表中的任何数据或记录对象成为结果的一部分,因为它占用了太多内存并且使用Ruby计算字段只会占用太多CPU而且耗时太长。
答案 0 :(得分:3)
在原始SQL中你需要这样的东西:
SELECT users.*, SUM(valuable.value) AS values_sum
FROM users
LEFT OUTER JOIN valuables ON users.id = valuables.user_id
GROUP BY users.id
因此,在ActiveRecord查询中翻译它将如下所示:
User.select('users.*, SUM(valuables.value) AS total_value')
.joins('LEFT OUTER JOIN valuables ON users.id = valuables.user_id')
请注意,您实际上并未从valuables
中选择任何列。
[10] pry(main)> @users = User.select('users.*, SUM(valuables.value) AS total_value').joins('LEFT OUTER JOIN valuables ON users.id = valuables.user_id')
User Load (1.4ms) SELECT users.*, SUM(valuables.value) as total_value FROM "users" LEFT OUTER JOIN valuables ON users.id = valuables.user_id
=> [#<User:0x007f96f7dff6e8
id: 8,
created_at: Fri, 05 Feb 2016 20:36:34 UTC +00:00,
updated_at: Fri, 05 Feb 2016 20:36:34 UTC +00:00>]
[11] pry(main)> @users.map(&:total_value)
=> [6]
[12] pry(main)>
然而,除非你想要manually load the associations,否则“default_scope”和“我仍然希望能够使用包含”要求可能有点高。
答案 1 :(得分:2)
方法1 :
"Locations":{
[groupName]:{
[user]:{
lat: "175.48598907719583",
lng: "-37.99470968516994",
time: "1454707169089"
},
},
}
请注意,哈希只包含有贵重物品的用户的条目。要获取所有用户(即使没有贵重物品的用户),您可以使用hash = User.joins(:valuables).group('users.id').sum('valuables.value')
hash.each { |uid, tval| puts "User ID #{uid} has total value #{tval}." }
代替includes
。
方法2 :
joins
我会选择方法1 和value_hash = Valuable.group(:user_id).sum(:value)
all_user_ids = User.pluck(:id)
all_user_ids.each do |uid|
tval = value_hash[uid] || 0
puts "User ID #{uid} has total value #{tval}."
end
。
编辑:在更好地理解问题之后:
includes