按周分组并在Rails中计算列值

时间:2015-12-29 07:20:12

标签: sql ruby-on-rails ruby database activerecord

希望在rails中使用简单的SQL查询(使用Active Record),我遇到了一些麻烦。

我想返回一个JSON响应,以便客户端可以使用以下数据结构:

{"2014-12-01-2014-12-07": {
        "foo": 100,
        "bar": 50,
        "baz": 20,
        "blah": 10,
    },
    "2014-12-08-2014-12-14": {
        "foo": 40,
        "bar": 550,
        "baz": 210,
        "blah": 10,

    }
}

foobarbazblah等可能是Foo模型中数组中可用的值(来自Foo :: PossibleStates) )。我想每周返回每种类型的总计数。我大致知道我将如何在Mongo(我更熟悉的世界)中解决这个问题,但是我遇到了SQL和Rails / Active Record中细微差别的问题。任何方向将不胜感激!这是我到目前为止所尝试的内容:

class FooController < ApplicationController
  def index
    start_date = params[:start_date]
    end_date = params[:end_date]
    @jsonFooData = Foo.group('created_at').group("workflow_state").sum('workflow_state')
  end
end

2 个答案:

答案 0 :(得分:0)

我认为这不是一件容易的事。

如果您使用的是postgres,可以通过一个sql和一个循环来实现:

# models/foo.rb

# call this Foo.count_by_week in your controller
def self.count_by_week
  raw_result = group_by_week_and_state.count

  # {['2014-12-01-2014-12-07', 'foo'] => 100, ['2014-12-01-2014-12-07', 'bar'] => 100, '...' => '...'}

  raw_result.each_with_object({}) do |(k, v), result|
     result[k[0]] ||= {}
     result[k[0]][k[1]] = v
  end
end

def self.group_by_week_and_state
  group("#{weekday_query(0)} || \'-\' || #{weekday_query(6)}").group('workflow_state')
end

# build sql part for day offset of week (0 => mon, 6 => sun)
def self.weekday_query(offset)
  "to_char(cast(date_trunc(\'week\', created_at) as date) + #{offset}, \'YYYY-MM-DD\')"
end

答案 1 :(得分:0)

results = Hash.new 0
counts = Hash.new 0 

# Get the results 'foos' with all the foo records grouped by beginning of the week. I'm using 'Monday' here but can be changed to any other weekday.
foos = Foo.all.group_by{|f| f.created_at.beginning_of_week(:monday)}

# loop through each grouped item
foos.collect do |foo| 
  # collect the workflow states and loop through them and count the unique workflow states.
  foo[1].collect{|f| f.workflow_state}.each do |ws| 
    counts[ws] += 1
  end
  # assign the workflow states counts to the beginning of the week
  results[foo[0]] = counts
  # reset the counter to new hash
  counts = Hash.new 0
end

# output the results
puts results