簡體   English   中英

Rails 5:如何通過關聯的模型屬性對模型進行排序,並使其與眾不同

[英]Rails 5: How to order models by associated model attribute, and make them distinct

我在rails中有一個作用域,應該通過最后一個聊天消息created_at屬性來訂購一組對話。 就像這樣:

class Conversation < ApplicationRecord
    has_many :chat_messages, -> { order(created_at: :asc) }, dependent: :nullify do
      def last_from_user
        from_user.order("created_at ASC").last
      end

      def last_delivered_from_user
        from_user.order("delivered_at ASC").last
      end

      def last_from_agent
        from_agent.order("created_at ASC").last
      end
    end

    default_scope { joins(:chat_messages).order("chat_messages.created_at desc").distinct }
end

例如,當一個ID為4的組織收到一條新消息時,我希望訂單為:

[4,1,2,3]

但是,我得到的是:

[1,2,3,4]

如果我刪除像這樣的獨特方法:

class Conversation < ApplicationRecord
    default_scope { joins(:chat_messages).order("chat_messages.created_at desc") }
end

會話被安排得很好,但是重復了:[4,1,2,3,4]

我的chat_message模型如下:

    class ChatMessage < ApplicationRecord

      # Associations
      # ------------------------------------------------------------

      belongs_to :conversation
    end

我無法使用“唯一”方法,因為這將使分頁無法正常工作。

但是,當對話中包含多個消息時,“區別”方法會弄亂順序。 此作用域按創建的順序(而不是我實際需要的順序)返回對話。

如果我們刪除Rails並只看一下SQL,它就會更加清晰。 您所遇到的是一個經典的SQL問題,即試圖獲取基於聯接的最大或最小排序的列表。

您正在運行這樣的查詢:

SELECT conversations.*
FROM conversations
INNER JOIN chat_messages
  ON chat_messages.conversation_id = conversations.id
ORDER BY chat_messages.created_at desc

您將在每一對對話和chat_messages中返回一行 這就是為什么重復的原因。

您不能對此使用不distinct

SELECT conversations.*
FROM conversations
INNER JOIN chat_messages
  ON chat_messages.conversation_id = conversations.id
ORDER BY chat_messages.created_at desc

ERROR 3065 (HY000): Expression #1 of ORDER BY clause is not in SELECT list,
references column 'test.chat_messages.created_at' which is not in SELECT list;
this is incompatible with DISTINCT

如果您使用select distinct conversations.*, chat_messages.created_at您將回到開始的地方。

我不確定.distinct在做什么,但是它可能會引發異常。


相反,請刪除帶有group by conversation.id的重復項。 現在您有了分組查詢,可以order by max(chat_messages.created_at) desc

select c.*
from conversations c
join chat_messages cm
  on cm.conversation_id = c.id
group by c.id
order by max(cm.created_at) desc

將其轉換為Rails ...

Conversations
  .joins(:chat_messages)
  .group(:id)
  .order("max(chat_messages.created_at) desc")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM