我有两种模式:
class User
end
class Message
belongs_to :sender, :class_name=> 'User'
belongs_to :recipient, :class_name=> 'User'
end
我想获取给定用户的所有好友,这些好友按最近的消息日期排序,在给定用户和他的好友之间的对话中出现,如果可能在同一查询中,则获取对话中的留言数量。
现在,我坚持这个:
Messages.all(:joins => :sender,
:conditions => ['sender_id = ? OR recipient_id = ?', some_user.id, some_user.id],
:select => 'users.*, sender_id, recipient_id, MAX(messages.created_at) as last_created, COUNT(messages.id) as messages_count',
:group => 'messages.sender_id, messages.recipient_id',
:order => 'last_created DESC'
该查询产生此输出:
A)
users.* | sender_id | recipient_id | MAX(last_created) | messages_count
user1 | 1 | 2 | bla | bla
user1 | 1 | 3 | bla | bla
user1 | 1 | 4 | bla | bla
因为messages.sender_id = user.id
加入的模型我只提取了 user1 记录,但我需要 user2 , user3 和 user4当 user1 只向他的好友发送消息时,该特殊情况下的记录。
b)中
users.* | sender_id | recipient_id | MAX(last_created) | messages_count
user2 | 2 | 1 | bla | bla
user3 | 3 | 1 | bla | bla
user4 | 4 | 1 | bla | bla
在情况B中,否则,我有我想要的东西 - 所有三个伙伴按照最近的消息日期排序,在给定用户和他的好友之间的对话中出现。
c)
users.* | sender_id | recipient_id | MAX(last_created) | messages_count
user1 | 1 | 2 | bla | bla
user3 | 3 | 1 | bla | bla
user4 | 4 | 1 | bla | bla
情况C. user2作为伙伴1的伙伴缺失导致:joins => :sender
。否则,如果:joins => :recipient
缺少user3和user4。那是饼干。 无论我们如何加入模特。如何在一个查询中解决这种情况?
答案 0 :(得分:2)
您需要select_extra_columns gem来返回join / aggregate列。假设您已安装gem,请修改您的User模型,如下所示。
class User
select_extra_columns
def friends_with_conversation
User.all(
:select => "users.*, b.last_message_at, b.message_count",
:joins => "
RIGHT JOIN
( SELECT IF(a.sender_id=#{self.id}, a.recipient_id,
a.sender_id) AS friend_id,
MAX(a.created_at) AS last_message_at,
COUNT(a.id) AS message_count
FROM messages AS a
WHERE a.sender_id = #{self.id} OR
a.recipient_id = #{self.id}
GROUP BY IF(a.sender_id=#{self.id}, a.recipient_id,
a.sender_id)
) AS b ON users.id = b.friend_id
",
:order => "b.last_message_at DESC",
:extra_columns => {:last_message_at=>:datetime, :message_count => :integer}
)
end
end
现在,您可以进行以下调用以获取朋友的详细信息。
user.friends_with_conversation.each do |friend|
p friend.name
p friend.last_message_at
p friend.message_count
end
您需要gem在查询返回的last_message_at
对象中返回message_count
和User
。
修改强> 我不熟悉PostgresSQL。粗略阅读文档表明,遵循SQL可能会有效。
:joins => "
RIGHT JOIN
( SELECT CASE WHEN a.sender_id=#{self.id}
THEN a.recipient_id
ELSE a.sender_id
END AS friend_id,
MAX(a.created_at) AS last_message_at,
COUNT(a.id) AS message_count
FROM messages AS a
WHERE a.sender_id = #{self.id} OR
a.recipient_id = #{self.id}
GROUP BY CASE WHEN a.sender_id=#{self.id}
THEN a.recipient_id
ELSE a.sender_id
END
) AS b ON users.id = b.friend_id
"
答案 1 :(得分:1)
看起来你想要一个替代的“连接”字符串(即不是:joins => :sender
)。
:joins => :recipient
会对情况B给出正确答案吗?
如果没有 - 您也可以将手工制作的SQL传递给:joins
密钥,然后根据需要加入表格。
看起来这里有一个很好的教程,涵盖了连接: http://www.railway.at/articles/2008/04/24/database-agnostic-database-ignorant/