简体   繁体   English

活动记录每日计数数组wrt created_at或Updated_at

[英]Active records daily count array w.r.t created_at or updated_at

I am working on a school project where I have tables class_standard and enrollments 我正在一个学校项目中,我有class_standard桌子class_standardenrollments

enrollments belongs_to class_standard and class_standard has many enrollments . enrollments belongs_to的class_standardclass_standard有许多enrollments

enrollments are created_at in different days. enrollments在不同的日期。 I want to get daily counts of enrollments in last 30 days in an array. 我想获取过去30天内阵列中的每日报名人数。

ie [# of enrollments 1st day, 2nd day, 3rd day, .....] 例如[第1天,第2天,第3天,.....的注册人数]

This is the sample of the code that gets the daily count of Enrollments created and stores them in an array. 这是代码示例,该代码获取创建的每日注册计数并将其存储在数组中。

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

What you want to do is select a count grouped by day. 您要选择按天分组的计数。 How exactly to achieve this depends on what database is used. 如何准确实现这一点取决于所使用的数据库。

Postgres: Postgres:

date_trunc('day', created_at)

MySQL: MySQL:

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

For other db's check the documentation for date functions. 对于其他数据库,请查阅有关日期函数的文档。

Altogether the query you want is something like this: 总共您想要的查询是这样的:

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

We can write this in ActiveRecord as: 我们可以在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))

But this gives an ActiveRecord::Relation of records which is not very useful. 但这给出了一个ActiveRecord :: Relation记录,这不是很有用。 To get the raw query values we want to use #select_all . 要获取原始查询值,我们要使用#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)

When you convert the results to an array you will get an array of hashes: 将结果转换为数组时,将获得一个哈希数组:

[{"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"}, ...]

You can extract the count by mapping the array: 您可以通过映射数组来提取计数:

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

If you want the results just for one (or more) ClassStandards just add an additional condition to the where clause: 如果只需要一个(或多个)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

Or you call it off the association: 或者您将其取消关联:

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

If you want to get count of all days including the days where there isn't any enrollment: 如果您想计算所有天数,包括没有注册的天数:

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

Output Example 输出范例

[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]

This will give you an array of all 30 days. 这将为您提供所有30天的阵列。 But this isn't seems an efficient code. 但这似乎不是有效的代码。 This will run 30 queries for each record. 每个记录将运行30个查询。

What seems better to me is group the records on created_at and get records for the days which have some records. 对我来说似乎更好的是将记录分组在created_at并获取具有某些记录的日期的记录。 ie excluding days with no record. 即排除没有记录的天数。

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

Output Example 输出范例

{Mon, 19 Nov 2018=>12}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM