活动记录 - 按 child 属性排序 parent
active record - sort parent by by child attributes
活动记录非常新。
我正在尝试使用活动记录来查询 'changes' 并按最接近 children 的 start_time 排序(ctasks 和 legacy_ctasks)。
如果更改有 ctasks 和 legacy_ctasks,排序时使用最早(最小)start_time。
一项更改必须至少有一个 ctask 或 legacy_ctask。
一个更改可以有很多 ctasks and/or 许多 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
按两个关联 table 中任一个的最大值排序有点粗糙。根据您执行此操作的频率和您的 performance/space 需求,您可以考虑在 changes
table 上缓存时间戳,以便您可以轻松地对其进行索引。
但我认为您可以采取几种方法。一种是同时加入 table 并按 changes.id 分组。我认为应该看起来像这样:
Change.select("changes.*")
.group("changes.id")
.left_joins(:ctasks, :legacy_ctasks)
.order("GREATEST(MAX(ctasks.start_time),MAX(legacy_ctasks.start_time))")
另一种选择是对每个 table 使用横向连接以从每个中提取最早的记录。这在 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)")
活动记录非常新。
我正在尝试使用活动记录来查询 'changes' 并按最接近 children 的 start_time 排序(ctasks 和 legacy_ctasks)。
如果更改有 ctasks 和 legacy_ctasks,排序时使用最早(最小)start_time。
一项更改必须至少有一个 ctask 或 legacy_ctask。
一个更改可以有很多 ctasks and/or 许多 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
按两个关联 table 中任一个的最大值排序有点粗糙。根据您执行此操作的频率和您的 performance/space 需求,您可以考虑在 changes
table 上缓存时间戳,以便您可以轻松地对其进行索引。
但我认为您可以采取几种方法。一种是同时加入 table 并按 changes.id 分组。我认为应该看起来像这样:
Change.select("changes.*")
.group("changes.id")
.left_joins(:ctasks, :legacy_ctasks)
.order("GREATEST(MAX(ctasks.start_time),MAX(legacy_ctasks.start_time))")
另一种选择是对每个 table 使用横向连接以从每个中提取最早的记录。这在 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)")