Ruby on Rails 3 签入/签出范围(按小时)

发布于 2024-12-09 11:19:28 字数 652 浏览 1 评论 0原文

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

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

8:00am - 8:59am : 12 visitors
9:00am - 9:59am : 5 visitors
10:00am - 10:59am : 4 visitors

...给定一个包含登记入住和退房时间的访问表。

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

我尝试过设置如下查询:

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

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

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

I'm using Ruby on Rails 3 and I have a "visit" model which stores a check_in and check_out datetime and I need to search through visits in a general date range and count the number of "visitors present" grouped by all hours of the day.

...i.e. I need something like:

8:00am - 8:59am : 12 visitors
9:00am - 9:59am : 5 visitors
10:00am - 10:59am : 4 visitors

...given a table of visits with a check in and check out time stored.

The idea is to take check-in and check-out times for "visits" and then determine how many visitors (assuming each visit logs one visitor, which it does by policy) were visiting during any given hour of the day in order to find out peak visiting times.

I've tried setting up queries like:

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

...and haven't quite hit on it because Rails stores dates in such an odd fashion (in UTC, which it will convert on database query) and it doesn't seem to be doing that conversion when I use something like EXTRACT in SQL...

...any idea how I can do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

自我难过 2024-12-16 11:19:29

也许类似的事情?

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 %>

Maybe something like that?!

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

EDIT:
Or you can grab all visits by day and filter it in 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

And in view:

<% visits_by_hour.each_with_index do |h, v| %>
  <%= "#{h}:00 - #{h}:59: #{v} visitors" %>
<% end %>
伏妖词 2024-12-16 11:19:29

感谢您的帮助 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 进行时间转换。

因此,我可以收集所有在小时范围内有小时的访问,然后压缩 nils 并计算剩下的内容。当我接触到它时,我感到很惊讶。我根本不需要任何自定义 SQL,正如我所想的那样(除非这是完全错误的,但它似乎可以处理一些测试数据)。

谢谢你们!

Thanks for your help Olexandr and mu, I managed to figure something out with the insight you gave me here.

I came up with this, and it seems to work:

#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

Then I can just dump out that hash in my view.

It seems the solution was a bit simpler than I thought, and doing it this way actually makes rails do the time conversions from UTC.

So, I could just collect all the visits which have hours in the hour range, then compact out the nils and count what's left. I was surprised once I hit on it. I didn't need any custom SQL at all as I thought I would (unless this is completely wrong, but it seems to be working with some test data).

Thanks guys!

我恋#小黄人 2024-12-16 11:19:28

看来您实际上对 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 只是一种工具,您的工具箱中应该有不止一种工具。另外,不要害怕向模型添加额外的数据整理和汇总方法,您的模型应该有一个接口,允许您在代码的其余部分清楚地表达您的意图。

Looks like you're not actually interested in the Visit objects at all. If you just want a simple summary then push AR out of the way and let the database do the work:

# 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

Then a = Visit.check_in_summary(Date.today - 1) will give you the summary for yesterday without doing any extra work. That demo implementation will, of course, have holes in the array for hours without any checkins but that is easy to resolve (if desired):

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

That version returns an array with 24 elements (one for each zero-based hour) whose values are the number of checkins within that hour.

Don't be afraid to drop down to SQL when it is convenient, AREL is just one tool and you should have more than one tool in your toolbox. Also, don't be afraid to add extra data mangling and summarizing methods to your models, your models should have an interface that allows you to clearly express your intent in the rest of your code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文