简体   繁体   中英

Looping through objects by date in rails

I'm trying to loop through records created during a date range by customer then create two arrays to pass to Chart.js. The first array is each day in the date range, the second is the total hosts scanned for the given day.

Chart.js is looking for these formats:

labels: ["3/11","3/12","3/13","3/14"] (a basic array) data: [12,13,14,55] (another basic array)

In my case the labels need to be each date within the given range (I'm just testing it right now with a 14 day range; and data would be the amount of hosts scanned on that given day (which might be 0).

I can get the total hosts scanned for a Company pretty easily:

count = 0
company.tests.each do |test|
  count += test.network_hosts.count
end

But I'm struggling to align the host count with a date range since a test

My code is working, but the count for the day is off by one. In this case, the results from a day like 3/2 are showing under 3/1, etc.

dates = []
array = []
hit = 0
today = Date.today
tests = company.tests.where(date: today - 30..today).order(date: :asc)
(today - 30..today).each{|date| dates.push(date.to_s)}
dates.each do |r|
  hit = 0
    tests.each do |t|
      if t.date.strftime("%Y-%m-%d") == r
        hit = hit + t.network_hosts.count
      end
    end
    array.push(hit)
  end
  return array
end

=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

The date range array that I'm feeing into Chart.js looks like:

today = Date.today
labels = []
(today - 30..today).each{ |date| labels.push(js_date_time_no_year(date))}
return labels

=> ["02/17", "02/18", "02/19", "02/20", "02/21", "02/22", "02/23", "02/24", "02/25", "02/26", "02/27", "02/28", "03/01", "03/02", "03/03", "03/04", "03/05", "03/06", "03/07", "03/08", "03/09", "03/10", "03/11", "03/12", "03/13", "03/14", "03/15", "03/16", "03/17", "03/18", "03/19"]

So the value 17 in the first array should be in position 14, not 13 as it is. and so on. I can easily adjust this in my code by going back 31 days in, but ideally I want the user to be able to click a 30/60/90 day button and not have the do the backend math to add 1 to the date range.

I think you should keep it simple. So it can easily be extended and code readability is higher.

Here is a snippet which does the same

grouped_data = company.tests.joins(:network_hosts).where(date: 30.days.ago.to_date..Date.today).order(date: :asc).group_by {|test| test.date.strftime("%m/%d")}

now

array = []
labels = []
(30.days.ago.to_date..Date.today).each do|day|
  label =  day.strftime("%d/%m")
  labels.push label
  array.push(grouped_data[label].try(:length) || 0)
end

Read here about group_by

grouped_data[label].try(:length) || 0 grouped_data[label].try(:length) || 0 will return the actual network hosts whose company was created for specific date and 0 for those days where no company was created

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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