简体   繁体   中英

Sort records based on number of rows in another table - Rails

So I have a users table and in my relationship, I have defined that a user has many submissions and submissions belong to a user. I want to sort the users table based on how many submissions they have.

submission model

class Submission < ActiveRecord::Base
    belongs_to :user
end

user model

class User < ActiveRecord::Base
    has_many :submissions, dependent: :destroy
end

The far I have gone is I'm able to get how many submissions a user has using this query

Submission.all.count(:group => "user_id")

With this for example I'm able to get the number of submissions a user with a specific id has

{1=>3, 2=>5} 

I want to have a sorted users table with the user with the highest number of submissions first. How can this be achieved in rails activerecord?

You can do what you want in 2 ways:


Using join, group by and order by count

User.select("COUNT(*) AS count_all, submissions.user_id AS submissions_user_id")
    .joins('LEFT JOIN submissions ON submissions.user_id = users.id')
    .group('submissions.user_id')
    .order('COUNT(submissions.user_id) DESC')

This will generate the following sql:

SELECT COUNT(*) AS count_all, submissions.user_id AS submissions_user_id FROM "users" LEFT JOIN submissions ON submissions.user_id = users.id GROUP BY submissions.user_id  ORDER BY COUNT(submissions.id) DESC

LEFT JOIN will get the users with 0 submissions too (if you have that situation)


Using counter_cache

The most efficient solutions for querying, in this context, is to use counter_cache This will enable you to run a query like this:

User.order('submissions_count DESC')

which translates to:

SELECT * FROM users ORDER BY submissions_count DESC

!!! If you want to implement this, especially in production, do a backup of your database before starting. !!!

Read counter_cache docs to understand what it is and how it can help you.

Add a new column on users table named submissions_count .

class AddSubmissionsCountToUsers < ActiveRecord::Migration
  def change
    add_column :users, :submissions_count, :integer, default: 0
    add_index  :users, :submissions_count
  end
end

Modify your Submission model and add counter_cache.

class Submission < ActiveRecord::Base
  belongs_to :user, counter_cache: true
end

If you have a production database update submissions_count to reflect the number of existing submissions:

User.find_in_batches do |group|
  group.each do |user|
    user_submissions_count = Submission.where(user_id: user.id).count // find how many subscription a user has
    user.update_column(:submissions_count, user_submissions_count)
  end
end

Every time a user will create/destroy a subscription, submissions_count will be incremented/decremented for that user to reflect the change.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM