1

私はRubyonRails 3を使用しており、check_inとcheck_outの日時を保存する「訪問」モデルがあり、一般的な日付範囲の訪問を検索して、「存在する訪問者」の数をすべての時間でグループ化する必要があります。日。

...つまり、次のようなものが必要です。

8:00 am-8:59 am:12人の訪問者
9:00 am-9:59 am:5人の訪問者
10:00 am-10:59 am:4人の訪問者

...チェックインとチェックアウトの時間が保存された訪問の表が与えられます。

アイデアは、「訪問」のチェックイン時間とチェックアウト時間を取得し、1日の特定の時間に訪問した訪問者の数(各訪問が1人の訪問者を記録すると仮定)を決定することです。ピーク訪問時間外。

次のようなクエリを設定してみました。

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 個の要素 (0 から始まる時間ごとに 1 つ) を含む配列を返します。

都合のよいときに SQL にドロップダウンすることを恐れないでください。AREL は単なる 1 つのツールであり、ツールボックスに複数のツールを用意する必要があります。また、追加のデータ マングリング メソッドと要約メソッドをモデルに追加することを恐れないでください。モデルには、コードの残りの部分で意図を明確に表現できるインターフェイスが必要です。

于 2011-10-10T19:19:25.247 に答える
0

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!

于 2011-10-12T13:53:55.697 に答える