我有一个表达式,按当前用户给出的星数来选择前三个评论
@event.reviews.sort_by { |r| -r.stars.select{ |s| s.user_id == current_user.id }.count }.first(3)
问题在于它将所有评论和星星都记录到内存中并在Ruby中执行此操作。如果没有在直接SQL中执行此操作,有没有办法在arel中实现相同的功能,以便数据库执行大部分计算而不是Ruby?
答案 0 :(得分:1)
您可以使用以下内容,counter
此处代表来自stars
的{{1}} current_user
的{{1}}
review
上面的sql查询将创建一个# Single query with inner join
@event.reviews.joins(:stars)
.select("reviews.*, stars.id ,SUM(stars.user_id = #{current_user.id}) AS counter ")
.group("reviews.id ")
.order("counter DESC").limit(3)
和reviews
的内部联接表。
根据这些表的大小,当您获取stars
时,为事件加载reviews
和stars
可能会更快。例如,
@event
上述方法将进行单个查询以获取与该事件相关的所有评论的所有星标。
如果您在同一请求的其他位置使用 # Eager loading with separate queries
@event = Event.find(params[:id]).includes(:reviews => :stars)
和stars
,那么最好使用reviews
急切加载它们。