Rails中按item_id分组、按score排序取每组前3并返回关联Book的实现问题
Rails 分组取Top N关联数据实现方案
首先要先在模型中声明好关联关系:
# app/models/item_statistic.rb class ItemStatistic < ApplicationRecord belongs_to :book end # app/models/book.rb class Book < ApplicationRecord has_many :item_statistics end
方案1:SQL窗口函数实现(推荐,大数据量性能优)
适配PostgreSQL、MySQL 8.0+等支持窗口函数的数据库,直接在数据库层完成筛选逻辑,避免全量加载数据:
# 先按item_id分组、按score倒序排序,每组取前3条记录 top_statistics = ItemStatistic.select( "*, ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY score DESC) AS rank_num" ).where("rank_num <= 3") # 预加载关联Book避免N+1查询,构造目标格式哈希 result = top_statistics.preload(:book).each_with_object({}) do |stat, hash| item_id = stat.item_id hash[item_id] ||= [] hash[item_id] << stat.book.attributes.symbolize_keys end
如果需要按score升序排序,删除ORDER BY score DESC中的DESC即可
方案2:Ruby层处理(适合小数据量,写法更简洁)
数据量不大的场景可以直接在Ruby层做分组筛选,不需要写原生SQL:
result = ItemStatistic.preload(:book) .order(score: :desc) .group_by(&:item_id) .transform_values do |stats| stats.take(3).map { |stat| stat.book.attributes.symbolize_keys } end
内容的提问来源于stack exchange,提问作者spirito_libero
相关产品推荐
相关产品推荐

