1

I have many User objects with created_at attribute e.g.

I get objects with @users = User.all

I want get the count of User objects with various ages from creation with

@users.size

for these date ranges:

yesterday
last week
last month
last year.

How can I do it?

I use mongoid.

dbenhur
  • 20,008
  • 4
  • 48
  • 45
hyperrjas
  • 10,666
  • 25
  • 99
  • 198

1 Answers1

2

You can write scopes for this:

class User
  include Mongoid::Document
  ...

  ## Scopes for calculating relative users
  scope :created_yesterday, lambda { where(:created_at.gte => (Time.now - 1.day)) }
  scope :created_last_week, lambda { where(:created_at.gte => (Time.now - 1.week)) }
  scope :created_last_month, lambda { where(:created_at.gte => (Time.now - 1.month)) }
  scope :created_last_year, lambda { where(:created_at.gte => (Time.now - 1.year)) }
  ...
end

The reason we need to use a lambda here is that it delays the evaluation of the Time.now argument to when the scope is actually invoked. Without the lambda the time that would be used in the query logic would be the time that the class was first evaluated, not the scope itself.

Now we can get the counts, by simply calling:

User.created_yesterday.count
User.created_last_week.count
...

If you want the objects:

@users_created_yesterday = User.created_yesterday

You can use @users_created_yesterday in the views.

Update

Well with yesterday, if you mean time between, yesterday beginning of day 0:00 and yesterday end of day 23:59, you will have to take Time zones into consideration.

Fo example, in your application.rb, if you have written:

# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
 config.time_zone = 'Central Time (US & Canada)'

If you have use this, all the times fetched by activerecord queries will be converted to this time zone, Central Time (US & Canada). In the database, all the times will be stored in UTC and will be converted to the time zone on fetching from the database. If you have commented out this line, default will be UTC. You can get all the time zones using the rake task rake time:zones:all or only the US timezones using rake time:zones:us.

If you want the time zone specified in the application.rb, you need to use Time.zone.now, in the following code. If you use Time.now in the following code, you will get the time zone according to the time zone of your server machine.

class User
  include Mongoid::Document
  ...
  scope :created_between, lambda { |start_time, end_time| where(:created_at => (start_time...end_time)) }

  class << self
    ## Class methods for calculating relative users
    def created_yesterday
      yesterday = Time.zone.now - 1.day
      created_between(yesterday.beginning_of_day, yesterday.end_of_day)
    end

    def created_last_week
      start_time = (Time.zone.now - 1.week).beginning_of_day
      end_time = Time.zone.now
      created_between(start_time, end_time)
    end

    def created_last_month
      start_time = (Time.zone.now - 1.month).beginning_of_day
      end_time = Time.zone.now
      created_between(start_time, end_time)
    end

    def created_last_year
      start_time = (Time.zone.now - 1.year).beginning_of_day
      end_time = Time.zone.now
      created_between(start_time, end_time)
    end
  end

  ..
  ..
end

So, you can write class methods and calculate start time and end time, supply it to the scope created_between, and you will be able to call them like User.created_yesterday, like we called before.

Credits: EdgeRails. Since it is Mongoid, I had to look up at Mongoid docs

hyperrjas
  • 10,666
  • 25
  • 99
  • 198
rubyprince
  • 17,559
  • 11
  • 64
  • 104
  • Thank you but If I add to my model `< AR` I get error. me too get the next error in my model: `ArgumentError (wrong number of arguments (2 for 1)): app/models/user.rb:17:in `block in '` Line 17 is `scope :created_yesterday, lambda { where("users.created_at >= ?", Time.now - 1.day) }` – hyperrjas Mar 16 '12 at 17:56
  • I'm using rails 3.1 + mongoid – hyperrjas Mar 16 '12 at 17:58
  • sorry, you are using mongoid, right..I am not familiar with mongoid..but a brief look into the documentation, I think my edit would be enough – rubyprince Mar 16 '12 at 18:01
  • sorry but I can not accept your response for me not works this code because this code its for mysql :( – hyperrjas Mar 16 '12 at 18:03
  • @hyperrjas..please see my edit once more..no more edits, I swear :) – rubyprince Mar 16 '12 at 18:05