I have an activity log that stretches across a few years. I have been asked to calculate weekly engagement for each user for the application. I define engagement as a user doing one or more logged activities in any given week.
How do I group those activities and count them by week for each user? I have read a lot of different posts, and there seems to be debate about whether ruby methods, sql or arel syntax are best. I don't have more than 500 users so performance is not a concern as much as something that is succinct.
I have successfully tried this:
user = User.first.activity_logs.group_by { |m| m.created_at.beginning_of_week }
# => {Mon, 11 Mar 2013 00:00:00 EDT -04:00=>
[#<ActivityLog id: 12345, user_id: 429, ... ]}
Then the only next step I can get to return anything without error:
user.map { |week| week.count } => [2, 2, 2, 2, 2, 2, 2, 2]
So it seems like I am making this too complicated. How do I succinctly count the number of activities by week and do that for each user?
I just want something that I can ultimately paste into a spreadsheet (for example, below) to make a heat map or some other chart for managers.
| User | Week | Activity|
| ------------- | :-------------: | -------:|
| jho | 2013-1 | 20 |
| bmo | 2013-1 | 5 |
| jlo | 2013-1 | 11 |
| gdo | 2013-2 | 2 |
| gdo | 2013-5 | 3 |
| jho | 2013-6 | 5 |
EDIT
As reference for others:
Rails 3.1
Using PostgreSQL 9.1.4
Here is the schema file from ruby on rails
create_table "activity_logs", :force => true do |t|
t.integer "user_id"
t.string "activity_type"
t.datetime "created_at"
t.datetime "updated_at"
end
| ------+| --------+| ----------------+| ----------------+ | ----------------+ |
| id | user_id | activity_type | created_at | updated_at |
| ------+| --------+| ----------------+| ----------------+ | ----------------+ |
| 28257 | 8 | User Signin | 2013-02-14 1... | 2013-02-14 1... |
| 25878 | 7 | Password Res... | 2013-02-03 1... | 2013-02-03 1... |
| 25879 | 7 | User Signin | 2013-02-03 1... | 2013-02-03 1... |
| 25877 | 8 | Password Res... | 2013-02-03 1... | 2013-02-03 1... |
| 19325 | 8 | Created report | 2012-12-16 0... | 2012-12-16 0... |
| 19324 | 9 | Added product | 2012-12-16 0... | 2012-12-16 0... |
| 18702 | 8 | Added event | 2012-12-15 1... | 2012-12-15 1... |
| 18701 | 1 | Birthday Email | 2012-12-15 0... | 2012-12-15 0... |
| ------+| --------+| ----------------+| ----------------+ | ----------------+ |
SOLUTION
Modifying @Erwin Brandstetter's command, I got the desired result like so on the command line:
ActivityLogs.find_by_sql("
SELECT user_id, to_char(created_at, 'YYYY-WW') AS week, count(*) AS activity
FROM activity_logs
GROUP BY 1, 2
ORDER BY 1, 2;")