Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Size of an ActiveRecord_Relation object

I have the following query:

User.joins(:posts).group('users.id').having('count(user_id) > 1')

The returned class is User::ActiveRecord_Relation.

If I call .size on it, it returns a hash. If I call .size.size I get the correct size returned.

Is this really how I should get the size of an ActiveRecord_Relation, or how is the correct way otherwise?

like image 897
Fellow Stranger Avatar asked Oct 12 '25 23:10

Fellow Stranger


1 Answers

It's important to understand why you get a hash when you call #size here.

#size will execute a SELECT COUNT(*) query if the association is not loaded yet. This is equivalent to calling #count. So you get a hash.

But if somehow the association has already been loaded into memory, #size won't execute any additional query, but will get the length of the association. In this case, the length of the hash. Try the following in console:

query = User.joins(:posts).group('users.id').having('count(user_id) > 1'); #don't load the association 
query.size   # => hash
query.size   # => length of the previous hash

So it's not a good idea to rely on chaining #size here unless you're sure the association wouldn't have been loaded before this. Instead, use #length for this:

User.joins(:posts).group('users.id').having('count(user_id) > 1').length  # => integer

#length doesn't execute the additional query, and will always load the whole association into memory so it's a bit slower and is hungrier. But in practice it's usually not an issue unless you're loading a huge amount of records.

By the way, if all you want is to find number of users with more than one post, there's no need for #join:

Post.group('user_id').having('count(user_id) > 1').length
like image 99
EJAg Avatar answered Oct 14 '25 14:10

EJAg