如何修复此 n+1 查询:将子关联限制为 JSON api 响应中的最新记录 [英] How to fix this n+1 query: Limiting child association to most recent record in JSON api response
问题描述
我正在尝试返回父记录列表,以及每个父母最近的子记录.
I am trying to return a list of parent records, along with each parents most recent child record.
在我的控制器中,我有:
In my controller I have:
def index
projects = current_user.projects.includes(:tasks)
render json: projects.as_json(
methods: [:most_recent_task],
), status: 200
end
方法 most_recent_task
使用了一种明确的方法 这里 总结如下:
The method most_recent_task
uses an approach articulated here and summarized below:
class Task < ApplicationRecord
class << self
def in_order
order(created_at: :asc)
end
def recent(n)
in_order.endmost(n)
end
def endmost(n)
all.only(:order).from(all.reverse_order.limit(n), table_name)
end
end
end
和
class Project < ApplicationRecord
has_many :tasks
def most_recent_task
tasks.recent(1)[0]
end
end
这种方法返回正确的 JSON 响应,但我现在显然正在处理针对每个请求的 Task
的 n+1 查询.
This approach returns the correct JSON response, but I am now obviously dealing with n+1 queries for Task
on every request.
我尝试过使用 :includes
和 :limit
链接作用域,但似乎无法解决这个问题.也许使用 JSON 序列化程序可以解决它?但我现在正试图避免这种额外的依赖.有什么建议吗?
I've tried chaining scopes, using :includes
and :limit
, but can't seem to crack this nut. Perhaps using a JSON serializer could solve it? But I am trying to avoid that extra dependency for now. Any advice?
推荐答案
一种解决方案是定义一个具有关联作用域的 has_one:
One solution is to define a has_one with an association scope:
has_one :most_recent_task, -> { order(created_at: :asc) }, class_name: "Task"
然后您可以使用 includes
来急切地加载数据:
You can then use includes
to eagerly load the data:
>> Project.includes(:most_recent_task).all
Project Load (0.3ms) SELECT "projects".* FROM "projects" LIMIT $1 [["LIMIT", 11]]
Task Load (0.5ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" IN (1, 2) ORDER BY "tasks"."created_at" ASC
请注意,它正在查询每个项目的所有任务,而不仅仅是最近的任务.但是没有 N+1,Project#most_recent_task
表现力很好.
Note that it's querying all tasks for each project, not just the most recent one. But there's no N+1, and Project#most_recent_task
is nicely expressive.
这篇关于如何修复此 n+1 查询:将子关联限制为 JSON api 响应中的最新记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!