Rails noob here...I'm trying to find the best option in my rails project. I have a sql query like this:
select sum(count) from (select count(user_id) as 'count' from accounts group by user_id having count(user_id) > 2) as A
All its trying to do is get the sum of count of users that have more than 2 accounts. While this sql query works fine by itself, I'm trying to find a way to translate this to Active Record. Users
and Accounts
are rails models in my project.
I'm assuming User has a has_many relationship with Accounts? In that case, you can do something like
User.find(id).accounts.count
and each time a user with a particular id has >= 2 accounts, you can add 1 to the total count.
Or you could do something like
count = 0
@users = User.all
@users.each do |user|
if user.accounts.count >= 2
count += 1
end
end
Hopefully this is something you were looking for.
timmy's solution should work, but will cause N+1 queries . You can use .includes to eager load what you need in order to minimize queries to the database (I too assume you have set up your has_many and belongs_to association between users and accounts). I believe this would be the optimized implementation:
users = User.includes(:accounts)
count = 0
users.each do |user|
count += 1 if user.accounts.count > 2
end
I believe you could even refactor this further by chaining on a .where, but I am not quite sure how. check the documentation page I linked to at the top.
Hope that helps.
As per the sql query provided by you, Account model (accounts table)
has a column named user_id
which you are using for grouping. First step is to group by user_id
and find user wise account counts. This will create a hash looking like { u1: n_acc1, u2: n_acc2 }
. The select statement selects all (key: value) user_id: n_accounts
pairs where n_accounts > 2
. Then you just need to map (value) n_accounts
into an array and apply sum
on it.
Account.group(:user_id).count
.select{ |user_id, n_accounts| n_accounts > 2 }
.map{ |user_id, n_accounts| n_accounts }
.sum
No need to use association and/or eager loading
. Should be faster than the other solutions. Also, issues a single db query to find grouped count, rest all calculations would be on ruby side.
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.