【问题标题】:active record - sort parent by by child attributes活动记录 - 按子属性排序父
【发布时间】:2021-08-31 19:58:30
【问题描述】:

对活动记录非常陌生。

我正在尝试使用活动记录来查询“更改”并按其孩子(ctasks 和 legacy_ctasks)最近的 start_time 对其进行排序。

如果变更有 ctasks 和 legacy_ctasks,排序时使用最早(最小)的 start_time。

一项更改必须至少有一个 ctask 或 legacy_ctask。

一个变更可以有很多 ctasks 和/或很多 legacy_ctasks

ctasks 和 legacy_ctasks 都有一个 start_time 字段:

t.datetime "start_time":

型号:

class Change < ApplicationRecord
    has_many :ctasks, -> { order "start_time ASC" }, dependent: :destroy
    has_many :legacy_ctasks, -> { order "start_time ASC" }, dependent: :destroy
end

class LegacyCtask < ApplicationRecord
  belongs_to :change, touch: true
end

class Ctask < ApplicationRecord
  belongs_to :change, touch: true
end

我目前的尝试非常悲伤:

Change.left_joins(:ctasks, :legacy_ctasks).order('ctasks.start_time ASC').order('legacy_ctasks.start_time ASC').distinct

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    从两个关联表中的任何一个中按最大值排序有点麻烦。根据您执行此操作的频率以及您的性能/空间需求,您可能会考虑在changes 表上缓存时间戳,以便您可以轻松地通过它进行索引。

    但我认为您可以采取几种方法。一种是通过changes.id 加入两个表和组。我认为应该是这样的:

    Change.select("changes.*")
      .group("changes.id")
      .left_joins(:ctasks, :legacy_ctasks)
      .order("GREATEST(MAX(ctasks.start_time),MAX(legacy_ctasks.start_time))")
    

    另一种选择是对每个表使用横向连接以从每个表中提取最早的记录。这在 AR 中并不容易,但性能应该更高,类似于:

    ctasks_joins_sql = <<-SQL
    LEFT OUTER JOIN LATERAL (
      SELECT ctasks.start_time FROM ctasks WHERE ctasks.change_id = changes.id 
      ORDER BY start_time
      LIMIT 1
    ) as ctasks ON true
    SQL
    legacy_ctasks_join_sql = <<-SQL
    LEFT OUTER JOIN LATERAL (
      SELECT legacy_ctasks.start_time FROM legacy_ctasks WHERE legacy_ctasks.change_id = changes.id 
      ORDER BY start_time
      LIMIT 1
    ) as legacy_ctasks ON true
    SQL
    
    Change.select("changes.*")
      .joins(ctasks_joins_sql)
      .joins(legacy_ctasks_join_sql)
      .order("GREATEST(ctasks.start_time, legacy_ctasks.start_time)")
    
    

    【讨论】:

    • 感谢您的反馈。我找到了另一个使用回调的解决方案。但我需要测试一下。但我想我可以在 Change 中添加一个计算列并使用回调将其更新为最早的 ctask/legacy_ctask start_time
    猜你喜欢
    • 2017-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多