【问题标题】:Generate count stats by hour, day, month and year按小时、天、月和年生成计数统计信息
【发布时间】:2012-07-18 00:34:39
【问题描述】:

我有一个表一个模型视图:

View(id: integer, created_at: datetime)

我想在一段时间内生成每个小时、天、月或年的观看次数,以便在图表上使用它们。我已经在做类似的事情了:

View.group('DATE(views.created_at)')
    .select("*, count(*) AS series_count, DATE(views.created_at) AS series_time")
    .where(:created_at => (Time.now-7.days)..Time.now)

这会导致:

2012-06-16 => 20
2012-06-17 => 12
2012-06-18 => 15
2012-06-20 => 38 # Issue: Didn't include a day with no records
2012-06-21 => 11
2012-06-22 => 76
  1. 第一个问题是它不会添加填充来替代天或月或没有记录的任何内容。

  2. 第二个问题是有时它会增加一天,导致 8 天!

  3. 第三个问题是,当我尝试显示每小时和其他时间周期的计数时,它变得非常棘手,有人能提出一个更好的解决方案吗?

基本上我正在制作一个包含在所有模型中的模块时间轴,以便于生成统计数据,例如:

include Timeline # on the model
Model.timeline(
      :time_column => :created_at,
      :period => (Time.now-24.hours)..Time.now,
      :by => :hours
    )

谢谢!

【问题讨论】:

  • 请指定您的 DBMS。是postgres吗?

标签: ruby-on-rails activerecord


【解决方案1】:

1) 有很多方法可以解决这个问题,但我不确定哪种方法更有效。所有这些都包括首先制作一个您想要显示的日期数组,然后添加结果子集中没有的内容或将您从数据库中获得的内容插入到地图中。我做了一些类似的东西来制作预期时间的数组:

class Time

  #Period is the number of seconds between each interval 
  def upto(end_time, period)

    division_count = (end_time.to_i - self.to_i) / period

    divisions = division_count.times.map { |div| self + (period * div) }

    divisions << end_time

  end

  #Period is the number of seconds between each interval 
  def downto(start_time, period)

    division_count = (self.to_i - start_time.to_i) / period

    divisions = division_count.times.map { |div| start_time + (period * div) }
    divisions

  end

end

要获取两天之间的天数,请按如下方式调用:

time_one.upto(time_two, 1.day.to_i)

警告:这将包括这两天。要获得 7 天的范围,请从 time_two 中删除一天。

time_one.upto(time_two - 1.day, 1.day.to_i

2) 这个问题是您使用的是当前时间而不是最后一小时。您需要回到最后一天/小时/分钟,然后从中减去。对于几天之间的范围,您可以在 2012 年 4 月这样做:

Time.utc(2012, 04)..Time.utc(2012, 05)

从四月第一天的午夜到四月最后一天的午夜。有效地获取当月的所有数据。您可以通过删除月份参数来多年执行此操作,并通过添加天参数来执行几天。 See usage here.

有几个小时,它有点复杂。您可以只创建一个新日期,只将您想要保留的内容转移到新日期,从而剥离您不需要的内容,然后从中减去。

3) 自从我完成 SQL 以来已经有一段时间了,所以我不能真正给你确切的代码,但你总是可以尝试格式化你的日期输出,所以它包括小时/分钟/等,所以当它将它分组,它会知道。即使将其格式化为字符串也可以。一种效率较低的方法是为每个时间范围单独调用。

【讨论】:

  • 谢谢你,问题是这可能不适用于每月周期,因为显然月份可以有 28、29、30 或 31 天。
  • 正如我在第 3 部分中所说,如果您只能获得您所在领域的月份,它将按月份分组。我将编辑 2 以反映我在代码之后的意思。
  • 另外,(Date.today.to_time - 7.days)..Date.today.to_time 仍然返回 8 天,Time.upto。它使用了:2012-07-10 00:00:00 +0100..2012-07-17 00:00:00 +0100
  • 是的,这就是我的扩展的意图。您可以根据需要轻松更改它或按照警告编辑进行说明。
猜你喜欢
  • 2021-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-24
  • 2014-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多