Den*_*ive 3 ruby sqlite postgresql activerecord ruby-on-rails
我将在命名范围中放入什么:by_unique_users以便我可以执行Comment.recent.by_unique_users.limit(3),并且每个用户只能获得一条评论?
class User
has_many :comments
end
class Comment
belongs_to :user
named_scope :recent, :order => 'comments.created_at DESC'
named_scope :limit, lambda { |limit| {:limit => limit}}
named_scope :by_unique_users
end
Run Code Online (Sandbox Code Playgroud)
在sqlite named_scope:by_unique_user,:group =>"user_id"工作,
但是它会在postgres上出现问题,postgres部署在生产PGError:ERROR:列"comments.id"必须出现在GROUP BY子句中或用于聚合函数
Postgres与MySQL和SQLite的不同之处在于它的处理方式GROUP BY.从本质上讲,它非常严格.让我们说你有.
id name
1 foo
2 bar
2 baz
Run Code Online (Sandbox Code Playgroud)
那你就是在做GROUP BY id.MySQL假设您只想丢弃除名字之外的所有名称.所以它会产生.
id name
1 foo
2 bar
Run Code Online (Sandbox Code Playgroud)
但是,在这种情况下,Postgres不会猜测分组方法.它需要有关如何对其他列进行分组的特定说明.它为此目的提供了所谓的聚合函数,在这种情况下,您正在寻找一个首先采用的函数.我找不到这样做的功能,但也许min()或者max()可以作为一个功能.在这种情况下,您需要使用:select => 'min(comments.id), min(comments.some_other_column)',除了user_id之外,您应该为每个列执行此操作.然后你可以使用:group =>'user_id'没有问题.
顺便说一句,min()并且max()接受字符串,不只是数字,所以他们应该对任何列工作.如果你想真正采取第一个,然后谷歌"postgres聚合首先"找到一些实现,或使用postgres数组.虽然这些会破坏与mysql和sqlite的兼容性.
更新
另一方面,如果获取最近的评论并不是太昂贵,那么让ruby处理独特的用户部分.
unique_comments = []
Comment.recent.each do |comment|
unless unique_comments.find{|c| c.user_id == comment.user_id}
unique_comments << comment
end
break if unique_comments.size > 2
end
Run Code Online (Sandbox Code Playgroud)
现在,您最多有3条来自不同用户的评论.