【问题标题】:rails query join, order by, group by issuerails query join, order by, group by issue
【发布时间】:2013-11-20 19:49:29
【问题描述】:

项目中有三个模型

  • 对话
  • conversation_message
  • 留言

Conversation.rb

class Conversation < ActiveRecord::Base
    #subject
    has_many :conversation_messages, :dependent => :destroy
    has_many :messages, :through => :conversation_messages, :dependent => :destroy, :order => "created_at DESC"
end

ConversationMessage.rb

class ConversationMessage < ActiveRecord::Base
  #conversation_id, message_id
  belongs_to :conversation
  belongs_to :message, :dependent => :destroy
end

消息.rb

#sender_id, receiver_id, message

has_one :conversation_message, :dependent => :destroy
has_one :real_conversation, :through => :conversation_message, :source => "conversation"

所以我想检索current_user 的所有对话,并希望按照收到或发送的最后一条消息的顺序显示它们。 还希望为其所有消息显示单个对话,并且对话必须按其中包含的消息排序。 使用 Rails 3.0

我尝试了以下查询,但在下面给了我一个错误 查询

@user_conversations = Conversation
.joins(:messages)
.where(["messages.receiver_id = ?  or messages.sender_id = ?", current_user.id, current_user.id ])
.group("conversations.id").order("messages.created_at DESC")

错误

PG::GroupingError: ERROR:  column "messages.created_at" must appear in the GROUP BY clause or be used in an aggregate function

【问题讨论】:

    标签: ruby-on-rails join group-by


    【解决方案1】:

    您需要在group 子句中包含messages.created_at

    @user_conversations = Conversation
    .joins(:messages)
    .where(["messages.receiver_id = ?  or messages.sender_id = ?", current_user.id, current_user.id ])
    .group("conversations.id, messages.created_at")
    .order("messages.created_at DESC")
    

    见:column "users.id" must appear in the GROUP BY clause or be used in an aggregate function

    【讨论】:

    • 我想显示单个会话的所有相关消息,并且会话列表必须按进入会话的消息排序。
    【解决方案2】:

    您可以通过使用来避免显示多个对话

    .order("max(messages.created_at) DESC")

    并从group 部分中删除messages.created_at

    @user_conversations = Conversation
    .joins(:messages)
    .where(["messages.receiver_id = ?  or messages.sender_id = ?", current_user.id, current_user.id ])
    .group("conversations.id")
    .order("max(messages.created_at) DESC")
    

    它为您提供“最新 cmets 排序的独特对话”。

    这不仅仅是通过messages.created_at 订购,而是通过更改maxminDESCASC 来完成你想要的工作,我猜。

    添加: 我写这个答案已经很多年了,我发现如果没有消息,这不会返回记录。
    为了处理您需要在查询中添加NULLS LASTNULLS FIRST(对于postgreql,我不知道对于mysql)。
    前任。 .order("max(messages.created_at) DESC NULLS LAST")

    【讨论】:

    • 哇,非常感谢。包含max() 是这个工作和不工作之间的区别 - 它让我的大脑好几天。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-31
    • 2014-01-30
    • 2015-02-17
    • 1970-01-01
    • 1970-01-01
    • 2018-06-27
    • 1970-01-01
    相关资源
    最近更新 更多