如何根据子类的属性对父类进行排序?

发布于 2024-10-30 08:14:34 字数 788 浏览 0 评论 0原文

在我看来,我有一个简单的要求:我想根据子类的属性对父类进行排序。

class owner
  has_many :tasks
end

class task
  belongs_to :owner
end

现在我想根据任务的截止日期对所有者进行排序,以便具有“最接近”截止日期的任务的所有者排在第一位,等等

我可以在 Ruby 中使用数组排序来完成此操作,但我的记录集是巨大,我需要使用 AR / DBMS 来完成此操作..

更新:
当我思考这个问题时,我想到了部分解决方案,尽管我不知道如何在 AR 中实现。

要根据任务对所有者进行排序,只有一项任务(每个所有者)相关,即截止日期最近的任务。

我如何使用 AR 来获取所有所有者,并按截止日期最接近的任务排序?

更新2:

Task.order("due_date DESC").maximum("due_date", :group => 'owner')

实际上会给我所有者对象,作为有序散列的一部分以正确的顺序排序([owner] =>“due_date”)。万岁!现在唯一的问题是,我如何告诉 AR eager_load 与所有者对象相关的所有任务。因为此时此刻,每次我

owner.tasks.each do |t|

在我的视图中调用时都会触发查询。

感谢任何帮助,我对这个(简单?)问题感到疯狂,
欧文

I have what seemed to me a simple requirement: I want to sort a parent class based on an attribute of its child class.

class owner
  has_many :tasks
end

class task
  belongs_to :owner
end

Now I want to sort the owners based on the due date on their tasks, so that the owner that has the task with the "closest" due date is first, etc

I can do this in Ruby with array sorting, but my record sets are huge and i need to do this with AR / DBMS..

UPDATE:
As I am pondering this question part of the solution occurred to me, although I don't know how to implement in AR.

To sort the owners based on their tasks, only a single task (per owner) is relevant, namely the one with the closest due date.

How would I use AR to fetch me all the owners, sorted by their task with the closest due date?

UPDATE 2:

Task.order("due_date DESC").maximum("due_date", :group => 'owner')

Will actually give me the owner objects, sorted in the right order as part of an ordered hash ( [owner] => "due_date"). Hooray! The only problem now is, how do I tell AR to eager_load all the associated tasks with the owner object. Because at this moment its firing a query everytime i call

owner.tasks.each do |t|

in my view.

Any help appreciated, i'm going nuts with this (simple??) problem,
Erwin

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

陌伤浅笑 2024-11-06 08:14:34

好吧,最后我自己想出了办法。

Owner.includes(:tasks).joins(:tasks).order("tasks.due_date").group(:id)

将根据任务中最接近的截止日期对所有者进行排序,并立即加载所有任务,从而生成单个查询。

更新:添加生成的 SQL 以响应下面 Mladen 的评论。

SELECT `owners`.* FROM `owners` 
INNER JOIN `tasks` ON `tasks`.`owner_id` = `owner`.`id` 
GROUP BY owner.id ORDER BY tasks.due_date DESC

干杯。

Ok, so in the end I figured it out myself.

Owner.includes(:tasks).joins(:tasks).order("tasks.due_date").group(:id)

will sort the Owners based on the closest due date in their tasks and will eager load all tasks, resulting in a single query.

Update: added the generated SQL in response to Mladen's comment below.

SELECT `owners`.* FROM `owners` 
INNER JOIN `tasks` ON `tasks`.`owner_id` = `owner`.`id` 
GROUP BY owner.id ORDER BY tasks.due_date DESC

Cheers.

情归归情 2024-11-06 08:14:34

发现这只能通过纯查询实现:

Owner.find_by_sql('SELECT `owners`.*,
                           (SELECT `tasks`.`due_date`
                            FROM `tasks`
                            WHERE `owners`.`id` = `tasks`.`owner_id`
                            ORDER BY `tasks`.`due_date` DESC LIMIT 1) AS `last_due_date`
                   FROM `owners`
                   GROUP BY `owners`.`id`
                   ORDER BY `last_due_date` DESC;')

如果需要访问 last_due_date 则添加到 Owner 模型:

def last_due_date
  if attributes['last_due_date']
    attributes['last_due_date']
  else
    tasks.order(due_date: :desc).limit(1).first.due_date if tasks.length > 0
  end
end

Found this possible only by pure query:

Owner.find_by_sql('SELECT `owners`.*,
                           (SELECT `tasks`.`due_date`
                            FROM `tasks`
                            WHERE `owners`.`id` = `tasks`.`owner_id`
                            ORDER BY `tasks`.`due_date` DESC LIMIT 1) AS `last_due_date`
                   FROM `owners`
                   GROUP BY `owners`.`id`
                   ORDER BY `last_due_date` DESC;')

If need access to last_due_date then add to Owner model:

def last_due_date
  if attributes['last_due_date']
    attributes['last_due_date']
  else
    tasks.order(due_date: :desc).limit(1).first.due_date if tasks.length > 0
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文