sql - ActiveRecord - 从每个组中选择第一条记录

标签 sql ruby-on-rails-3 postgresql activerecord

我想要每个用户发送的最新消息。这是示例数据

表:对话

sender  receiver message                        date
============================================================
    1   2   "hi"                            "2013-03-04 09:55:01.122074"
    2   1   "hello"                         "2013-03-04 09:55:32.903975"
    1   2   "have you done with the taks?"  "2013-03-04 09:57:46.383007"
    2   1   "almost..."                     "2013-03-04 09:58:55.783219"
    2   1   "should be able to finish 2day" "2013-03-04 09:59:28.950705"
    2   3   "shall we start?"               "2013-03-04 10:01:16.842725"
    3   2   "give me a minute"              "2013-03-04 10:01:41.994589"
    3   2   "let us start"                  "2013-03-04 10:02:14.04551"

对于id为2的用户,我应该可以得到以下两条记录

1   2   "have you done with the taks?"  "2013-03-04 09:57:46.383007"        
3   2   "let us start"                  "2013-03-04 10:02:14.04551"

这是我的解决方案

模型:用户

class User < ActiveRecord::Base
has_many :chats_received, class_name: 'Conversation', foreign_key: 'receiver_id',order: "created_at DESC"
end

模型:对话

class Conversation < ActiveRecord::Base
  attr_accessible :message, :read

  belongs_to :sender, class_name: 'User'
  belongs_to :receiver, class_name: 'User'

  def most_recent_chat_received_from_connected_users
    connected_users_chats = . . . # Get all conversations which are sent to current user. e.g., user with id 2
    chats_grouped_by_senders = connected_users_chats.group_by { |conversation| conversation.sender_id }
    chats_grouped_by_senders.inject([]){|memo , (sender_id, conversations)| memo << conversations.first; memo}
  end
end

获取连接用户的最新消息:

user = User.find 2
user.most_recent_chat_received_from_connected_users

虽然此解决方案有效,但它会为两个用户之间的每次转化选择和创建模型。我也觉得这不是获取所需行的 Rails 方式。

我一直在使用 postgresql。当我尝试在模式上使用组方法时,出现以下错误。

ActiveRecord::StatementInvalid: PG::Error: ERROR:  column "conversations.id" must appear in the GROUP BY clause or be used in an aggregate function

有没有更好的方法来获得相同的结果?

最佳答案

我不确定如何在 User 的实例上调用 most_recent_chat_received_from_connected_users,它是 Conversation 类的实例方法没有得到错误,但我会向对话模型添加一个自定义查找器:

class Conversation < ActiveRecord::Base
  # ...

  def self.most_recent_for(user_id)
    select('DISTINCT ON (sender_id) *').where(reciever_id: user_id).order("sender_id, created_at DESC")
  end

  # For MySQL you could have used:
  #
  # def self.most_recent_for(user_id)
  #   where(reciever_id: user_id).group("sender_id").order("created_at DESC")
  # end

  # ...
end

现在您可以通过以下方式在您的 Controller 中获得所需的对话:

@conversations = Conversation.most_recent_for(current_user.id)

关于sql - ActiveRecord - 从每个组中选择第一条记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15206809/

相关文章:

c# - 解析现有的 "complex"SQL 语句并转换为对自定义 API 调用的调用

java - 如何进行数据库查询的 JUNIT 测试

ruby - 从散列中删除空值

ruby-on-rails - Rails 页面缓存和自动扩展的问题

postgresql - 如何在 PostgreSQL 中制作交叉表?

c# - 外键约束错误但不应该发生

sql - 使用 SQL 获取和删除查询字符串

ruby-on-rails - 你如何使用 ActionDispatch::Routing::RouteSet 识别路径?

postgresql - 无法阅读与go-pg的“一对多”关系

postgresql-按每个元素中的单词对数组进行排序