我有两个模型:User
和Message
,它们通过has_many
关系连接起来。我想获得一个users
列表,按照上一条消息的时间戳排序。
class User < ActiveRecord::Base
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :user
end
当我这样做时:
@users = User.includes(:messages).order('messages.created_at DESC').limit(5)
似乎订购消息,抓取最新的5条消息,然后返回与这些消息相关联的用户。所以用户数量可以少于5.我想确保我得到5个用户。
我希望查询获取每个请求的最新消息,订购最后的消息,然后返回带有最新消息的用户。所以我想要这样的东西:
@users = User.includes(:messages).order( <messages.last.created_at DESC> )
理想情况下,解决方案会对数据库进行排序,因为我想使用paginate。如果它与我使用Postgres相关。
答案 0 :(得分:6)
我可能会优先考虑phoet提到的向用户添加属性的解决方案,例如last_message_posted_at
,并使用touch: true
在消息创建时更新该属性。这简化了在需要提取用户列表时必须执行的查询。这也为您的应用程序提供了更具可读性(IMO)的链:
@users = User.all.order(:last_message_posted_at)
=> "SELECT \"users\".* FROM \"users\" ORDER BY \"users\".\"last_message_posted_at\" ASC"
这也允许您为用户模型添加一个漂亮而简单的范围
scope: :by_recent_message, ->{ order(:last_message_posted_at) }
User.by_recent_message.limit(5)
它还取决于使用此@users
范围的时间和频率。对于我来说,在每次拉出用户列表时,比在复杂的SQL查询中添加几毫秒的邮件时间更好。
- 为那些不熟悉触控语法的人编辑
触摸文档:http://apidock.com/rails/v4.2.1/ActiveRecord/Persistence/touch
class User < ActiveRecord::Base
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :user, touch: true
end
然后进行查询(给最近最后一条消息的用户):
@user = User.includes(:messages).order(updated_at: :desc )
答案 1 :(得分:0)
你可以尝试一下
Message.group(:user_id).joins(:users).order('max(messages.created_at) desc')
答案 2 :(得分:0)
您可以使用左连接而不是包含
@users = User.joins("LEFT JOIN messages on messages.user_id = users.id").order('messages.created_at').limit(5)