2015-11-04 19 views
1

我在我的头上试图获得统计数据在n天的过程中。我不关心输出格式,只要它按顺序显示日期,并将值显示为数组... all_data查询(下面)将获得确定时间段内的所有值,但它赢得了'为没有值的日期创建行。目标是能够输出:填写空白日期的分组查询,返回一些空行

# Get 10 (for example) days of data-> 

[ 
    {date:'datetime-day-ago-10', values: [{foo:'bar', foo2:'bar2', foo3:'bar'3}]} 
    {date:'datetime-day-ago-9', values: [{foo:'bar', foo2:'bar2', foo3:'bar'3}]} 
    {date:'datetime-day-ago-8', values: []} 
    {date:'datetime-day-ago-7', values: [{foo:'bar', foo2:'bar2', foo3:'bar'3}]} 
    {date:'datetime-day-ago-6', values: []} 
    {date:'datetime-day-ago-5', values: []} 
    {date:'datetime-day-ago-4', values: [{foo:'bar', foo2:'bar2', foo3:'bar'3}]} 
    {date:'datetime-day-ago-3', values: [{foo:'bar', foo2:'bar2', foo3:'bar'3}]} 
    {date:'datetime-day-ago-2', values: []} 
    {date:'datetime-day-ago-1', values: []} 
] 

这里是我在这里使用的方法。

def counts 

    from = params[:days].to_i.days.ago.to_time.beginning_of_day 
    to = 0.days.ago.to_time.end_of_day 

    all_data = current_user.values.all 
       .where(field_id: params[:field_id], created_at: from .. to) 
       .where.not(input: nil) 
       .order(input: :desc) 
       .group_by { |value| value['created_at'].to_date} 
       .map {|k,v| [k,v]} 

    grouped = (0..params[:days].to_i-1).to_a.inject([]) do |memo, i| 
     if all_data[i].present? 
      date = all_data[i][0].to_time 
      values = all_data[i][1].group_by { |value| value.input }.map { |k, v| {input:k, count:v.length} }.sort! { |x,y| x['input'] <=> y['input']} 
      total = 0 
      values.each do |value| 
       total = total + value[:count] 
      end 
     else 

      # This is where I can't figure out how to assign a date for rows which have no data. 

      date = ((i-params[:days].to_i+1)*-(1)).days.ago.beginning_of_day 

     end 
     memo << {'date': date, 'total': total || 0, 'values': values || []} 
     memo 
    end 

    grouped = grouped.sort_by { |day| day['date'] } 
    render json: grouped 
end 

# Sample of entire output for 10 days 

0: {date: "2015-10-31T00:00:00.000-07:00", total: 15,…} <- 10-31-2015 HAS VALUES 
1: {date: "2015-11-01T00:00:00.000-07:00", total: 49,…} <- 11-01-2015 HAS VALUES 
2: {date: "2015-11-02T00:00:00.000-08:00", total: 10,…} <- 11-02-2015 HAS VALUES 
3: {date: "2015-11-03T00:00:00.000-08:00", total: 21,…} <- 11-03-2015 HAS VALUES 
4: {date: "2015-10-30T00:00:00.000-07:00", total: 0, values: []} 
5: {date: "2015-10-31T00:00:00.000-07:00", total: 0, values: []} \ 
6: {date: "2015-11-01T00:00:00.000-07:00", total: 0, values: []} - No matter what I try I can't get these dates to be the 5 days before 10-31-2015... 
7: {date: "2015-11-02T00:00:00.000-08:00", total: 0, values: []}/
8: {date: "2015-11-03T00:00:00.000-08:00", total: 0, values: []} 
9: {date: "2015-11-04T00:00:00.000-08:00", total: 0, values: []} <- 11-04-2015 This should appear up there^under the last HAS VALUES row 

那么,如何正确地创建空值行的日期?然后,我怎样才能确保它们落入正确的顺序?就像我说过的,我对此感到头痛。算法不是我的一杯茶。

回答

0

这可能会在部分有点特殊,但在这里就是我如何设法得到所需的输出。我决定让这个轨道控制器为我提供我需要的Angular Google Charts的确切输入信息,但我已经明确了直接回答问题的位置。根据填写缺失日期和缺失行值的方法:

 from = params[:from] || (params[:days].to_i-1).days.ago.to_date 
     to = params[:to] || 0.days.ago.to_date 

     all_data = current_user.values.all 
        .where(field_id: params[:field_id], created_at: from.beginning_of_day .. to.end_of_day) 
        .where.not(input: nil) 
        .order(input: :desc) 
        .group_by { |value| [value['created_at'].to_date, value['input']] } 
        .map { |k, v| {'date': k.first, 'input': k.last, 'count': v.length} } 

     # the object which will hold the data to be returned 

     grouped = {:cols => [], :rows => [] } 

     # Populate columns with a determined set of values for inputs 
     diffvals = Array.new 
     all_data.each { |day| diffvals.push day[:input] } 
     diffvals = diffvals.uniq 
     diffvals.each { |input| grouped[:cols].push({'id': "#{input}-id", 'label': input, 'type': 'number'}) } 
     grouped[:cols].unshift({'id': 'day', 'label': 'Date', 'type': 'string'}) 

     ## 
     ## This and the next commented section answer the question: 
     ## 
     # Create a set of dates that the actual data will be merged into 
     zeros = Array.new 
     (0..params[:days].to_i-1).each do |n| 
      diffvals.each do |input| 
       hash = Hash.new 
       hash[:date], hash[:input], hash[:count] = n.days.ago.to_date, input, 0 
       zeros.push hash 
      end 
     end 

     ## 
     ## 
     ## 
     # Group the data by date after mapping the actual data onto the premade set of dates 
     data_by_date = zeros.map do |first_hash| 
      all_data.each do |second_hash| 
       if first_hash[:date] == second_hash[:date] && first_hash[:input] == second_hash[:input] 
        first_hash[:count] = second_hash[:count] 
        break 
       end 
      end 
      first_hash 
     end.group_by { |i| i[:date]} 

     # Populate rows of data 
     data_by_date.each_with_index do |(date, values), day| 
      # 
      # The first column is the date 
      grouped[:rows][day] = {c: [{ v: date }] } 

      # 
      # Then columns of value inputs 
      (0..grouped[:cols].length-2).each { |value| grouped[:rows][day][:c].push({v: values[value][:count] }) } 

      # 
      # Then a column for the total of all value counts 
      grouped[:rows][day][:c].push({v: values.map {|v| v[:count]}.reduce(0, :+) }) 

     end 

     grouped[:cols].push({'id': "s", 'label': "Total", 'type': 'number'}) 

     render json: grouped 

下面是一组样本数据。喜欢的颜色,3种可能的颜色选择。超过5天:

cols: 
    0: {id: "day", label: "Date", type: "string"} 
    1: {id: "Red-id", label: "Red", type: "number"} 
    2: {id: "Green-id", label: "Green", type: "number"} 
    3: {id: "Blue-id", label: "Blue", type: "number"} 
    4: {id: "s", label: "Total", type: "number"} 
rows: 
    0: {c: [{v: "2015-11-01"}, {v: 18}, {v: 23}, {v: 8}, {v: 49}]} 
    1: {c: [{v: "2015-11-02"}, {v: 4}, {v: 4}, {v: 2}, {v: 10}]} 
    2: {c: [{v: "2015-11-03"}, {v: 5}, {v: 16}, {v: 0}, {v: 21}]} 
    3: {c: [{v: "2015-11-04"}, {v: 0}, {v: 0}, {v: 0}, {v: 0}]} 
    4: {c: [{v: "2015-11-05"}, {v: 0}, {v: 1}, {v: 6}, {v: 7}]} 

这正是所需要的对角谷歌图表插件

0

可能是,你可以来自本方:

grouped = (from.to_date..to.to_date).each do |dt| 
    existing_data = all_data.detect{ |data| data.first == dt } 
    if existing_data 
    # you code for existing date 
    else 
    # you code for non-existing date 
    end 
    # ... 
end 

# And, I think, it is not required in this case 
#grouped = grouped.sort_by { |day| day['date'] }