有效记录每日计数数组,包含created_at或Updated_at

时间:2018-11-19 10:07:58

标签: ruby-on-rails activerecord rails-activerecord

我正在一个学校项目中,我有表class_standardenrollments

enrollments属于class_standard,而class_standard有许多enrollments

enrollments是在不同的日期创建的。我想获取过去30天内阵列中的每日报名人数。

即[第一天,第二天,第三天.....的报名人数]

3 个答案:

答案 0 :(得分:0)

这是代码示例,可获取创建的每日注册计数并将其存储在数组中。

arr = [] #initialize an array
(0..29).each do |x| #run a loop for 30 days
  date = Time.now - x.days #get a specific day
  arr << Enrollment.where(created_at: date.midnight..date.end_of_day).count #get count of enrollments on a specific day and add this to your array
end
arr = arr.reverse #reverse the array, because you want the today's count as last item of the array

答案 1 :(得分:0)

您要执行的操作是选择按天分组的计数。如何准确实现这一目标取决于所使用的数据库。

Postgres:

date_trunc('day', created_at)

MySQL:

date_format(created_at, '%Y-%m-%d')

对于其他数据库,请查阅文档中有关日期函数的信息。

您想要的查询总共是这样的:

SELECT 
  count(*) AS count, 
  date_trunc('day', created_at) AS day 
FROM "enrollments" 
WHERE (created_at >= ?) -- one month ago 
GROUP BY day 
ORDER BY day

我们可以在ActiveRecord中将其编写为:

Enrollment.select("count(*) AS count, to_char(created_at, 'YYYY-MM-DD') AS day")
  .group("day")
  .order("day")
  .where(created_at: (1.month.ago..Time.current))

但是这提供了一个ActiveRecord :: Relations记录,这不是很有用。要获取原始查询值,我们要使用#select_all

sql = Enrollment.select("count(*) AS count, date_trunc('day', created_at) AS day")
  .group("day")
  .order("day")
  .where("created_at >= ?", 1.month.ago)
  .to_sql

results = Enrollment.connection.select_all(sql)

将结果转换为数组时,将获得一个哈希数组:

[{"count"=>10, "day"=>"2018-10-20 00:00:00"}, {"count"=>10, "day"=>"2018-10-21 00:00:00"}, {"count"=>10, "day"=>"2018-10-22 00:00:00"}, {"count"=>10, "day"=>"2018-10-23 00:00:00"}, {"count"=>10, "day"=>"2018-10-24 00:00:00"}, {"count"=>10, "day"=>"2018-10-25 00:00:00"}, ...]

您可以通过映射数组来提取计数:

results.map {|r| r["count"] }

如果只希望一个(或多个)ClassStandards的结果,只需在where子句中添加一个附加条件:

sql = Enrollment.select("count(*) AS count, date_trunc('day', created_at) AS day")
  .group("day")
  .order("day")
  .where("created_at >= ?", 1.month.ago)
  .where(class_standard: @class_standard)
  .to_sql

或者您将其取消关联:

sql = @class_standard.enrollments
  .select("count(*) AS count, date_trunc('day', created_at) AS day")
  .group("day")
  .order("day")
  .where("created_at >= ?", 1.month.ago)
  .to_sql

答案 2 :(得分:0)

如果您想计算所有天数,包括没有注册的天数:

daily_enrollments = []
i = 29
while i >= 0
  daily_enrollments >> Enrollments.where( created_at: Time.zone
                                                          .now
                                                          .beginning_of_day-i.day..
                                                      Time.zone
                                                          .now
                                                          .end_of_day-i.day).count

  i = i-1
end

输出示例

[0,0,0,5,4,0,0,0,5,0,23,0,0,23,0,0,1,0,11,0,21,32,44,0,0,9,6,3,22,1]

这将为您提供所有30天的阵列。但这似乎不是有效的代码。每个记录将运行30个查询。

对我来说更好的方法是将记录分组在created_at上,并获取具有某些记录的日期的记录。即排除无记录的天。

Enrollments.where(created_at: Time.current - 30.days..Time.current)
           .group("date(created_at)")
           .count
           .sort
           .to_h

输出示例

{Mon, 19 Nov 2018=>12}