我有一个表达式,根据当前用户给他们的星数选择前三名评论
@event.reviews.sort_by { |r| -r.stars.select{ |s| s.user_id == current_user.id }.count }.first(3)
问题在于它将所有评论和星标都拉到内存中,并在 Ruby 中执行此操作。如果没有在直接 SQL 中执行此操作,有没有办法在 arel 中实现相同的操作,以便数据库完成大部分计算而不是 Ruby?
我有一个表达式,根据当前用户给他们的星数选择前三名评论
@event.reviews.sort_by { |r| -r.stars.select{ |s| s.user_id == current_user.id }.count }.first(3)
问题在于它将所有评论和星标都拉到内存中,并在 Ruby 中执行此操作。如果没有在直接 SQL 中执行此操作,有没有办法在 arel 中实现相同的操作,以便数据库完成大部分计算而不是 Ruby?
可以用下面的,counter
这里代表一个stars
fromcurrent_user
的个数review
# 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)
上面的 sql 查询将创建一个reviews
和的内连接表stars
。
根据这些表的大小,预先加载reviews
和stars
获取@event
. 例如
# Eager loading with separate queries
@event = Event.find(params[:id]).includes(:reviews => :stars)
上述方法将进行一次查询以获取与事件相关的所有评论的所有星。
如果您在同一请求中的其他地方使用stars
and reviews
,那么最好使用includes
.