You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails如何用单条Active Record查询获取每个feed_id的10条最新Entry记录

实现方案

核心思路

借助数据库窗口函数ROW_NUMBER()实现分组排序取TopN,全程仅生成1条SQL查询,无N+1问题,性能优异,可直接在GraphQL resolver中使用。

代码实现

1. 窗口函数版本(推荐,适配PostgreSQL、MySQL 8.0+)

在Entry模型中新增可复用scope:

class Entry < ApplicationRecord
  belongs_to :feed

  # 按feed分组取最新limit条记录,默认取10条
  scope :latest_per_feed, ->(limit = 10) do
    # 给每个feed下的entry按发布时间倒序排名
    ranked_entries = select(
      "entries.*, ROW_NUMBER() OVER (PARTITION BY feed_id ORDER BY published_at DESC) AS feed_entry_rank"
    )
    # 筛选每个feed排名前limit的记录,保持排序规则
    from(ranked_entries, :entries)
      .where("feed_entry_rank <= ?", limit)
      .order(feed_id: :asc, published_at: :desc)
  end
end

使用方式

# 取所有feed各自最新10条
@entries = Entry.latest_per_feed
# 自定义取最新5条
@entries = Entry.latest_per_feed(5)
# 关联Feed数据避免N+1查询(适合GraphQL返回feed关联字段场景)
@entries = Entry.latest_per_feed.includes(:feed)
# 支持链式追加过滤条件,比如仅查询指定feed的最新10条
@entries = Entry.latest_per_feed.where(feed_id: [1,2,3])

2. 低版本MySQL兼容方案(MySQL 8.0以下)

如果使用的MySQL版本不支持窗口函数,可以用相关子查询实现:

scope :latest_per_feed, ->(limit = 10) do
  where(
    "SELECT COUNT(*) FROM entries e2 
    WHERE e2.feed_id = entries.feed_id 
    AND e2.published_at >= entries.published_at <= ?", limit
  ).order(feed_id: :asc, published_at: :desc)
end

验证方法

执行以下代码可确认结果符合预期:

Entry.latest_per_feed.group_by(&:feed_id).each do |feed_id, entries|
  puts "Feed#{feed_id}返回条目数:#{entries.size}" # 预期输出都是10
end

内容的提问来源于stack exchange,提问作者DK92

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 01:36:05