Rails: три последних комментария с уникальными пользователями - PullRequest
3 голосов
/ 25 мая 2010

что бы я поместил в названную область: 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, который развернут на производстве PGError: ERROR: столбец "comments.id" должен появляться в предложении GROUP BY или использоваться в статистической функции

Ответы [ 3 ]

6 голосов
/ 20 июня 2010

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 «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 комментариев от разных пользователей.

0 голосов
/ 27 мая 2010

Обычно предложение order выглядит следующим образом:

named_scope :recent, :order => 'created_at DESC'

Вы можете попробовать это.

0 голосов
/ 25 мая 2010

Именованная область может не работать, но вы можете заставить Rails выполнять ручной запрос (От Geek Skillz ).

Item.find( :all, :order => 'comments.created_at DESC', :select => 'DISTINCT user' )[0, 3]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...