1

我正在使用 Ruby on Rails 3,我有一个“访问”模型,它存储了 check_in 和 check_out 日期时间,我需要在一般日期范围内搜索访问并计算按所有小时分组的“访问者”数量天。

...即我需要类似的东西:

上午 8:00 - 上午 8:59:12 名访客
上午 9:00 - 上午 9:59:5 名访客
上午 10:00 - 上午 10:59 : 4 位访客

...给定一张包含签入和签出时间的访问表。

这个想法是记录“访问”的签入和签出时间,然后确定在一天中的任何给定时间有多少访问者(假设每次访问记录一个访问者,这是根据政策执行的)在一天中的任何给定时间访问,以便找到高峰访问时间。

我尝试设置查询,例如:

eight_am_visits = Visit.where("EXTRACT(HOUR_MINUTE FROM check_in) <= 859").where("EXTRACT(HOUR_MINUTE FROM check_out) >= 800")

...并且还没有完全成功,因为 Rails 以一种奇怪的方式存储日期(在 UTC 中,它将在数据库查询中转换)并且当我使用 EXTRACT 之类的东西时它似乎没有进行这种转换SQL...

...知道我该怎么做吗?

4

3 回答 3

1

也许是这样的?!

t = Time.now
eight_am_visits = Visit.all(:conditions => ['check_in > ? and check_in < ?', Time.utc(t.year, t.month, t.day, 8), Time.utc(t.year, t.month, t.day, 8, 59)])

编辑: 或者您可以按天获取所有访问并在 Rails 中对其进行过滤:

t = Time.now
visits = Visit.all(:conditions => ['created_at > ? and created_at < ?', Time.utc(t.year, t.month, t.day - 1), Time.utc(t.year, t.month, t.day + 1)])
visits_by_hour = []
(0..23).each do |h|
  visits_by_hour << visits.map {|e| e if e.created_at > Time.utc(t.year, t.month, t.day, h) && e.created_at < Time.utc(t.year, t.month, t.day, h, 59)}.count
end

并认为:

<% visits_by_hour.each_with_index do |h, v| %>
  <%= "#{h}:00 - #{h}:59: #{v} visitors" %>
<% end %>
于 2011-10-10T15:52:01.723 回答
1

看起来您实际上对 Visit 对象根本不感兴趣。如果您只想要一个简单的摘要,那么将 AR 推到一边,让数据库来完成工作:

# In visit.rb
def self.check_in_summary(date)
    connection.select_rows(%Q{
        select extract(hour from check_in), count(*)
        from visits
        where cast(check_in as date) = '#{date.iso8601}'
        group by extract(hour from check_in)
    }).inject([ ]) do |a, r|
        a << { :hour => r[0].to_i, :n => r[1].to_i }
    end
end

然后a = Visit.check_in_summary(Date.today - 1)会给你昨天的总结而不做任何额外的工作。当然,该演示实现将在数组中出现几个小时没有任何签入的漏洞,但这很容易解决(如果需要):

def self.check_in_summary(date)
    connection.select_rows(%Q{
        select extract(hour from check_in), count(*)
        from visits
        where cast(check_in as date) = '#{date.iso8601}'
        group by extract(hour from check_in)
    }).each_with_object([0]*24) do |r, a| # Don't forget the arg order change!
        a[r[0].to_i] = r[1].to_i
    end
end

该版本返回一个包含 24 个元素(每个从零开始的小时一个)的数组,其值是该小时内的签到次数。

方便时不要害怕使用 SQL,AREL 只是一种工具,您的工具箱中应该有不止一种工具。此外,不要害怕向模型添加额外的数据处理和汇总方法,您的模型应该有一个接口,可以让您在其余代码中清楚地表达您的意图。

于 2011-10-10T19:19:25.247 回答
0

感谢您的帮助 Olexandr 和 mu,我设法根据您在这里给我的洞察力找到了一些东西。

我想出了这个,它似乎工作:

#grab the data here, this is nice because 
#I can get other stats out of it (which I don't show here)
@visits = Visit.where(:check_in => @start_date..@end_date, :check_out => @start_date..@end_date).where("check_out IS NOT NULL");

#Here we go
@visitors_present_by_hour = {}
(0..23).each do |h|
  # o.o Ooooooh.... o_o Hee-hee! ^_^
  @visitors_present_by_hour[h] = @visits.collect{|v| v.id if v.check_in.hour <= h and v.check_out.hour >= h}.compact.count
end

然后我可以在我的视图中转储该哈希。

似乎解决方案比我想象的要简单一些,这样做实际上使 rails 可以从 UTC 进行时间转换。

所以,我可以只收集小时范围内的所有访问,然后压缩 nil 并计算剩下的内容。我一碰上就惊呆了。我根本不需要任何自定义 SQL,因为我想我会(除非这是完全错误的,但它似乎正在处理一些测试数据)。

多谢你们!

于 2011-10-12T13:53:55.697 回答