繁体   English   中英

Rails ActiveRecord加入作用域中的最新子级

[英]Rails ActiveRecord joining to most recent child in scope

我目前正在尝试编写一个工作人员,该工作人员必须检查最近孩子的状态并根据该状态对其进行排队。 例如,找到年龄最大的孩子在学校的父母

class Parent
  has_many :children
end
class Child
  belongs_to :parent
  lookup_for :status, symbolize: true
end

目前我的范围是:

Parent.joins(:children).
      where("children.birth_date =
            (SELECT MAX(children.birth_date)
             FROM children
             WHERE children.parent_id = parents.parent_id").
      where('children.status = ?', Status[:in_school]').pluck(:parent_id)

似乎应该有一个更好的方法来执行此操作。 有任何想法吗

为了澄清起见,我正在寻找所有最大的孩子还在上学的父母

如果您在查询中经常使用第一个/或最后一个孩子,我会将其添加为父项中的字段

class Parent
  belongs_to :youngest_child, class_name: Child, inverse_of: :parent
end

好的,您可以将某些逻辑推入joins()语句中,如下所示,但我看不出如何才能摆脱必须在某个地方进行子查询的麻烦。

Parent.joins(%Q{left join children on children.parent_id = parents.id
                  and children.birth_date = (select max(birth_date) from children 
                  where children.parent_id = parents.id)}).
                where('children.status = ?', Status[:in_school]')

看起来像那样。 高温超导

或者,您可以使用order and last查找最后一个孩子,然后检查该孩子在内存中的状态。 这种方法最多只能带一个孩子,因此表现合理。 如下所示:

child=Child.order(:birth_date).joins(:parent).last
parent.do_stuff if child.in_school?

您的查询有效-完成工作,并且清楚您要做什么。 我在我现在正在处理的应用程序中的相似关联上测试了您的模式, ActiveRecord将所有模式正确地组合到一个查询中,并且花费了1.4ms

如果要优化性能,可以使用联接来获取最老的孩子,而不是子查询:

Parent.joins("INNER JOIN (
                SELECT c1.*
                FROM children c1
                LEFT JOIN children c2 ON (c1.parent_id = c2.parent_id AND c1.birthdate > c2.birthdate)
                WHERE c2.parent_id IS NULL
              ) c ON parent.parent_id = c.parent_id")
              .where('children.status = ?', Status[:in_school])
              .pluck(:parent_id)

由于它使用了一种手动外部联接,因此它的用途不太清楚,但是它也允许嵌套联接也使用索引。 在与上述相同的测试方案中,此操作在0.9毫秒内执行了相同的查询(几乎快了两倍)。 那是在一个很小的数据库中,只有几百条记录。 拥有数百万条记录,差异将非常明显。

感谢这个StackOverflow的答案 ,为联接模式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM