在我的rails应用程序中,我有用户和列表。这些列表属于用户。列表包含user_id,其中包含正在创建列表的用户ID。
用户可以是高级用户,黄金用户或白银用户。
我想要的是每个高级用户,选择一个随机列表以显示在高级列表中。
我可以在O(n ** 2)时间或n + 1查询中执行以下操作:
users_id = User.where(:role => "premium").pluck[:id]
final_array = Array.new
users_id.each do |id|
final_array << Listing.where(:user_id => id).sample(1)
end
final_array
有更好的方法吗?
答案 0 :(得分:1)
你可以试试这个:
listings = Listing.select(
<<~SQL
DISTINCT ON (users.id) users.id,
listings.*,
row_number() OVER (PARTITION BY users.id ORDER BY random())
SQL
)
.joins(:user)
.includes(:user)
.where(users: { role: :premium })
它为每个高级用户提供随机列表。
它产生对db的唯一请求,并且它不会为获取列表的用户提出额外请求,因此您可以自由地执行以下操作:
listings.each do |listing|
p listing.user
end
答案 1 :(得分:0)
random_user_listings = []
User.includes(:listings).where(role: "premium").find_each do |user|
random_user_listings << user.listings.sample(1)
end
random_user_listings
答案 2 :(得分:-1)
要避免N + 1查询,您需要将它们组合起来,执行一次查询,如下所示:
list = Listing.includes(:user).where(:role => "premium").sample(1)
随意处理列表而不是列表。因为现在你正在处理变量,而不是查询。
ids = list.pluck(:user_id).uniq
像上面一样获取id的数组并像你一样做进一步的步骤(但是有list,而不是Listing) 需要注意的是,当你处理模型时,你正在处理QUERY。避免在循环语句中执行此操作。