Reputation: 1721
I have a model like this:
class Event
include Mongoid::Document
include Mongoid::Timestamps
scope :range, lambda {|start, finish|
where(:created_at => {'$gte' => start,'$lt' => finish}) if start && finish
}
end
And I need a hash of the number of events grouped by the day they happened:
{"2011-11-07"=>2, "2011-10-25"=>10, "2011-04-03"=>1, "2011-05-13"=>1, "2011-03-23"=>1, "2011-11-08"=>4, "2011-06-12"=>1, "2011-10-26"=>6}
I can get exactly that from the console using this rather unwieldy chain:
Event.range(4.months.ago, Time.now).to_a.
group_by{ |e| e.created_at.to_date }.
map{ |date, events| [date.to_s, events.count]}.
inject({}) { |r, i| r[i.first] = i.last; r }
I'd really like to put this into a scope or class method so that I can just write:
Event.range(4.months.ago, Time.now).daily
Any ideas on how to do this?
UPDATE:
Just FYI, I've tried each of the following solutions.
scope :daily, lambda { to_a.group_by{ |e| e.created_at.to_date }.
map{ |date, events| [date.to_s, events.count]}.
inject(ActiveSupport::OrderedHash.new) { |r, i| r[i.first] = i.last; r } }
and
def self.daily
to_a.group_by{ |e| e.created_at.to_date }.
map{ |date, events| [date.to_s, events.count]}.
inject(ActiveSupport::OrderedHash.new) { |r, i| r[i.first] = i.last; r }
end
Both fail. Backtrace:
> Event.range(2.week.ago, Time.now).daily
/my_app/event.rb:37: warning: default `to_a' will be obsolete
NoMethodError: undefined method `created_at' for Event:Class
from /my_app/event.rb:37:in `daily'
from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/core_ext/enumerable.rb:26:in `group_by'
from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/core_ext/enumerable.rb:25:in `each'
from /var/bundler/turtle/ruby/1.8/gems/activesupport-3.0.7/lib/active_support/core_ext/enumerable.rb:25:in `group_by'
from /my_app/event.rb:37:in `daily'
from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/criteria.rb:366:in `send'
from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/criteria.rb:366:in `method_missing'
from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/named_scope.rb:120:in `with_scope'
from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/criteria.rb:365:in `send'
from /var/bundler/turtle/ruby/1.8/gems/mongoid-2.2.0/lib/mongoid/criteria.rb:365:in `method_missing'
from (irb):57
from :0
Upvotes: 2
Views: 1365
Reputation: 10907
class method will not work as Event.range(4.months.ago, Time.now).daily
will require method daily to be defined on criteria and scope will not work as scope needs to return a criteria. Your best bet at the moment is to create a class method daily and use it like Event.daily(start, finish)
class Event
include Mongoid::Document
include Mongoid::Timestamps
scope :range, lambda {|start, finish|
where(:created_at => {'$gte' => start,'$lt' => finish}) if start && finish
}
def self.daily(start, finish)
daily_events = {}
self.range(start, finish).each do |event|
date_str = event.created_at.to_date.to_s
daily_events[date_str] ||= 0
daily_events[date_str] += 1
end
return daily_events
end
end
Upvotes: 1