Eric's thoughts

ruby, rails, and more

count v.s. lenght v.s. size

leave a comment »

there are couple difference between count and length, generally speaking, count does’t load the array so it is faster. However, there are situation count won’t give you an accurate number
here is an example

suppose you have three tables ‘users’, ‘roles’, and the join table ‘roles_users’, and you want to all active users that has role of ‘user’ or ‘admin’
Here is how to get it in rails:

named_scope :active, :joins=> :roles,
     :conditions=>['state=? and roles.name in (?) ', 'active', ['user', 'admin'] ], :group=>'id'

here group is necessary otherwise you will get duplicate users records if users has more than one role.

Here is where length different than count:
say joe is the only user and he has both user and admin roles

User.active.count # returns 2
User.active.length # returns 1

It is easy to figure out why through SQL:
the named_scope translate to

select u.id, u.first_name, u.email
from users u
inner join roles_users ru on ru.user_id = u.id
inner join roles r on r.id = ru.role_id
where u.state = 'active' and r.name in ('user', 'admin')
group by u.id;

the count translates to

select count(*), u.id, u.first_name, u.email
from users u
inner join roles_users ru on ru.user_id = u.id
inner join roles r on r.id = ru.role_id
where u.id = 2 and r.name in ('user', 'admin')
group by u.id;
without group by
+----+------------+--------------------+
| id | first_name | email              |
+----+------------+--------------------+
|  1 | Joe        |    joe@example.com |
|  1 | Joe        |    joe@example.com |
+----+------------+--------------------+
5 rows in set (0.00 sec)

with group by
+----+------------+--------------------+
| id | first_name | email              |
+----+------------+--------------------+
|  1 | Joe        |    joe@example.com |
+----+------------+--------------------+
1 row in set (0.00 sec)

using count and here is why it returns 2
+----------+----+------------+--------------------+
| count(*) | id | first_name | email              |
+----------+----+------------+--------------------+
|        2 |  1 | Joe        |    joe@example.com |
+----------+----+------------+--------------------+
1 row in set (0.00 sec)

the bottom line: don’t use count when using :group

p.s. for more difference between length, size and count, read this blog post: http://rhnh.net/2007/09/26/counting-activerecord-associations-count-size-or-length

Advertisement

Written by ericzou

June 20, 2009 at 5:24 pm

Posted in rails programming

Tagged with ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.