2009-05-24 3 views
29

Я делаю подсчет статистики в своем продукте. Пользователь выполнил ряд операций, скажем, опубликовал комментарии. Я хочу показать им, сколько комментариев они отправили в неделю за последний месяц или месяц за последний год.Группировка по неделям/месяцам/etc & ActiveRecord?

Есть ли способ с activerecord, чтобы сгруппироваться таким образом? Лучше всего просто сделать это вручную - перебирать суммирование записей на основе моих собственных критериев?

class User < ActiveRecord::Base 
    has_many :comments 
end 

class Comments < ActiveRecord::Base 
    belongs_to :user 
end 

@user.comments(:all).map {|c| ...do my calculations here...} 

или есть лучший способ?

спасибо! Орен

ответ

26

В этом случае лучшим решением для меня было либо сделать это в прямой SQL, или использовать функцию ActiveRecord group_by:

@user.all.group_by{ |u| u.created_at.beginning_of_month } 
+10

'group_by' - это не метод ActiveRecord, а метод Ruby на' Enumerable'. – Laurens

+0

Просто использование 'u.created_at.month' короче –

+11

Пожалуйста, не то, что это будет загружать все записи из базы данных, создавать экземпляры объектов ActiveRecord, анализировать даты в объектах, поддерживаемых часовым поясом ActiveSupport, - всего лишь для подсчета количества записей. –

13

Мое предположение было бы что-то вроде:

@user.comments.count(:group => "year(created_at),month(created_at)") 

Dry-код, YMMV

+0

Я считаю, что это будет сгруппировать по месяцам через годы - так что если у вас есть два года данных, все вещи в январе 1-го и 2-го года. То, что я ищу, - это способ рассказать о 24 например, сколько месяцев в месяц. – teich

+0

Вы также можете добавить условие для ограничения года: условия => [: created_at, "> # {.months.ago}"]. Опять же, непроверенный, но должен быть возможен с чем-то подобным. –

+0

Это похоже на mysql specific – Tachyons

2

Отъезд has_activity плагин.

+0

Спасибо за указатель. Похоже, has_activity - только mysql. Мой хозяин производства - postgresql. – teich

66

В Postgres вы можете сделать:

@user.comments.group("DATE_TRUNC('month', created_at)").count 

чтобы получить:

{"2012-08-01 00:00:00"=>152, "2012-07-01 00:00:00"=>57, "2012-09-01 00:00:00"=>132} 

Он принимает значения от «микросекунд» до «тысячелетия» для группировки: http://www.postgresql.org/docs/8.1/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC

+4

Так намного быстрее, чем использование ruby ​​перечислимого group_by! –

+0

Wojtek, а как же тогда, когда ничего не было создано за месяц? Вы ничего не получите за этот месяц. –

+1

@MattSmith Я так считаю. К счастью, легко получить значение по умолчанию при чтении значений из вывода этого запроса: '' 'output.fetch (« 2012-08-01 00:00:00 », 0)' '' –

16

Вот уточненная версия

@user.comments.group("year(created_at)").group("month(created_at)").count 
4

Использование group_by

@user.comments.group_by(&:week) 

class User < ActiveRecord::Base 
    def week 
    some_attribute_like_date.strftime('%Y-%W') 
    end 
end 

Это даст вам сгруппированный список в формате YYYY-WW

2

Заканчивать дата группы gem

https://github.com/ankane/groupdate

У этого есть последние коммиты, работает с postgresql, легко интегрируется с графиком для быстрого построения графика и работает с часовыми поясами!

+0

GroupDate работает только с UTC, поэтому, если вы используете другой часовой пояс в своей базе данных, рассмотрите альтернативы. – msdundar

Смежные вопросы