我将在命名范围中放入什么: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
在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
那你就是在做GROUP BY id
.MySQL假设您只想丢弃除名字之外的所有名称.所以它会产生.
id name 1 foo 2 bar
但是,在这种情况下,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
现在,您最多有3条来自不同用户的评论.