如何修复此 n+1 查询:将子关联限制为 JSON api 响应中的最新记录 [英] How to fix this n+1 query: Limiting child association to most recent record in JSON api response

查看:17
本文介绍了如何修复此 n+1 查询:将子关联限制为 JSON api 响应中的最新记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试返回父记录列表,以及每个父母最近的子记录.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆