【问题标题】:Group by Week and Count Column Values in Rails在 Rails 中按周分组并计算列值
【发布时间】:2015-12-29 07:20:12
【问题描述】:

希望在 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

【问题讨论】:

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


    【解决方案1】:

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

    如果你使用的是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
    

    【讨论】:

    • 我希望以一种不需要 db 必须是 postgres 的方式来实现这一点;如果我使用更简单的东西,比如 SQLite,我会怎么做?
    • 我遇到的主要问题是按周分组结果;当我运行 Foo .select(:id, :workflow_state, :created_at).where(created_at: start_date..end_date) .group_by{ |e| e.created_at.beginning_of_week(:sunday) } 时,我得到一个难以处理的数组。
    • 对于 sqlite,将您的 weekday_query 更改为 "date(created_at, \'weekday #{offset}\', \'-7 days\')"
    • 上面代码的一个注释:我认为group_bygroup 慢很多,因为它使用了额外的 ruby​​ 循环。
    • 太棒了——谢谢!我会试试这个。从 JS 世界来到 Rails,所以使用这些哈希/sql 查询有点新
    【解决方案2】:
    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-08
      • 2021-07-07
      • 2022-07-06
      • 2021-11-23
      • 2020-11-06
      • 2017-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多