在我的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
有没有更好的方法
你可以试试这个:
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
random_user_listings = []
User.includes(:listings).where(role: "premium").find_each do |user|
random_user_listings << user.listings.sample(1)
end
random_user_listings
要避免 N+1 查询,您需要将它们组合在一起,像这样执行一次查询:
list = Listing.includes(:user).where(:role => "premium").sample(1)
随意处理列表而不是列表。因为现在您处理的是变量,而不是查询。
ids = list.pluck(:user_id).uniq
获取像上面这样的 id 数组并像您一样执行进一步的步骤(但使用列表,而不是列表(需要注意的是,当你处理模型时,你正在处理QUERY。避免在循环语句中执行此操作。