AnApprentice
AnApprentice

Reputation: 110960

How to group a query result with active record?

I have the following model:

ProfileViews (id, user_id, viewer_id)

I am trying to return all user_views, which are grouped by viewer_id ... Note viewer_id can nil, which is something I want to return. I can say viewed 20 times by nil etc...

Why does this not work?

@profile_views = ProfileView.select('*').where(:user_id => current_user.id).group(:viewer_id)   

Upvotes: 1

Views: 342

Answers (2)

mu is too short
mu is too short

Reputation: 434665

Your query doesn't work because you're using PostgreSQL (or some similarly strict database) and your SELECT list doesn't match your GROUP BY. Everything in your SELECT must either be inside an aggregate function (such as COUNT, AVG, ...) or it must appear in your GROUP BY clause; some databases, such as MySQL and SQLite, will take a guess to remove the ambiguity but other databases, such as PostgreSQL, will not. I'd guess that you're seeing an error similar to:

ERROR:  column "X" must appear in the GROUP BY clause or be used in an aggregate function

You're probably looking for something more like this:

@profile_views = ProfileView.where(:user_id => current_user.id)
                            .count(:group => :viewer_id)

That will give you a simple Hash in @profile_views which maps viewer_id (including nils) to the number of views.

That bit of AR is equivalent to this SQL:

select viewer_id, count(*)
from profile_views
where user_id = #{current_user.id}
group by viewer_id

You'll note that everything in the SELECT is either in the GROUP BY or an aggregate.

You can't get the ProfileView objects at the same time as the counts. When you add a GROUP BY, you're collapsing rows that have the same viewer_id and once the rows have lost their identities, there is no way for the database to choose which row should be used to instantiate the ProfileView.

Upvotes: 1

ScottJShea
ScottJShea

Reputation: 7111

I do not think you can have select(*) in a group statement. You might try select count(viewer_id) or whatever grouping you are going for.

Update

You can see more examples here

Upvotes: 0

Related Questions