2014-01-11 32 views
0

假設我有一個有多個回覆的家長評論。父母和孩子的created_at排序的最佳方式是什麼?

class Comment < ActiveRecord::Base 
    has_many :replies 

class Reply < ActiveRecord::Base 
    belongs_to :topic 

我想通過created_at訂購我的意見,如果他們有一個新的回覆,我想是父母 - 評最最新回覆的created_at,而不是自己的created_at進行排序。

因此,如果例如我有3條評論,其中一條發佈爲第1天,第2天和第3天。第1天是最早的,但第2天有回覆,今天發佈,我該如何排序其結果必然是:

[ Day 2, Day 3, Day 1 ] 

凡2日發生了最近的活動,比本來在當天早些時候公佈的第3天評論更近一些。

這將是什麼方法?

+1

我很確定這是一個「向我們展示你迄今爲止的工作」類型的downvote。我冒昧地對你的問題的最後一句話進行了改寫,因此看起來你並不需要別人寫你自己的代碼。 –

回答

2

處理日期,通過你的模型是最好的做法:

class Comment < ActiveRecord::Base 
    has_many :replies 
end 

class Reply < ActiveRecord::Base 
    belongs_to :comment, touch: true 
end 

注意touch: truebelongs_to: comment關聯。通過updated_at保存Reply

現在只是爲了當選擇你的意見時,這將更新父Commentupdated_at屬性。

+2

請注意,這種方法意味着每個回覆都會對被回覆的評論進行鎖定,直到事務提交。因此,一次最多隻能有一個tx影響任何給定的評論。這可能是好的,但是在採取這種方法時也應該考慮。兒童更新鎖定父母也可能暴露死鎖風險。 –

+0

我認爲在這種情況下,鎖將幾乎不會被察覺。如果需要大量的時間來保存答覆記錄,那麼有些事情是非常錯誤的。此外,對評論行的任何進一步更新將僅排隊少量時間,而不是完全阻止。 – Jon

+0

當然,服務員只會阻止持有tx的鎖提交。當你將這種策略應用到競爭資源的樹上時,這實際上只是一個問題,你會在一個父對象上發生大量活動,等等。 –

1

我想像這樣的東西可能是「好的」,但查看查詢計劃。 (我只處理LINQ和SQL Server自己 - 因人而異。)

select * from comments c 
left join (select r.comment_id, max(r.created_at) as created_at 
      from replies r 
      group by r.comment_id) lr 
on lr.comment_id = c.comment_id 
order by isnull(lr.created_at, c.created_at) desc 
2

對於那個最好的查詢(如最好的查詢)是添加一個額外的last_activity列。維護後者(自動使用觸發器或某些RoR內置糖)並在其上添加索引。然後,您可以使用普通查詢來獲取該列所排序的行。

另一種選擇是聚合的醜陋連接(請參閱一小時前的答案)。它不會很漂亮,隨着桌子的大小不斷增加,它會執行極其

1

一個LEFT JOIN到最新響應(其可能不存在,因此LEFT)後,使用(SQL標準)COALESCEORDER BY。但是從commentsSELECT列,根據您的要求:

SELECT c.* 
FROM comments c 
LEFT JOIN (
    SELECT comment_id, max(created_at) AS created_at 
    FROM replies 
    GROUP BY 1 
) r USING (comment_id) 
ORDER BY COALESCE(r.created_at, c.created_at) DESC 

因爲從邏輯上講,回覆得來的意見後。如果不是這樣,那麼您應該使用GREATEST(r.created_at, c.created_at)

相關問題