我将在命名范围内添加什么: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
on sqlite named_scope:by_unique_user,:group => “user_id”有效,
但是它会在postgres上出类拔萃,后者会在生产中部署 PGError:错误:列“comments.id”必须出现在GROUP BY子句中或用于聚合函数
答案 0 :(得分:6)
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()
接受字符串,而不只是数字,所以它们应该适用于任何列。如果你想真正采用的第一个,那么google for“postgres aggregate first”来找到一些实现,或者使用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条来自不同用户的评论。
答案 1 :(得分:0)
命名范围可能不起作用,但您可以强制Rails进行手动查询(来自Geek Skillz)。
Item.find( :all, :order => 'comments.created_at DESC', :select => 'DISTINCT user' )[0, 3]
答案 2 :(得分:0)
通常,订单子句如下所示:
named_scope :recent, :order => 'created_at DESC'
您可能想尝试一下。