内部动态键上的Rails PostgreSQL jsonb GROUP BY查询

时间:2019-05-14 05:53:07

标签: ruby-on-rails postgresql activerecord jsonb

我有一个ActiveRecord模型,我们将其命名为API::Response,其中有一个名为error_messages的列,该列存储API调用失败时的错误消息。

API::Response的结构类似于:

#<API::Response:0x0000000019579298
 id: "fffefdae43c0",
 api_id: "11c91374f10e",
 parent_id: nil,
 code: "ABC123",
 meta_field: "{}",
 lock_version: 1,
 created_at: Thu, 01 Feb 2019 15:28:37 UTC +00:00,
 updated_at: Tue, 09 Oct 2019 20:32:03 UTC +00:00,
 version: 1538352000,
 error_messages: {"api_failure_1"=> "API failure reason 1", "api_failure_2"=> "API failure reason 2"},
 output_data: { "foo" => "bar"},
 override_applied: false>

我想要做的是获得一个结果,该结果是我在keys列中按error_messages进行分组,并获取每个键的出现次数:

像这样的东西

key                   | count
-----------------------------
api_failure_1         |  1
api_failure_2         |  3
some_other_failure    |  n
...

其中keys jsonb字段中的error_messages是动态的。

我试图做类似的事情

API::Response.where.not("error_messages = '{}'").group("error_messages").count

但这只是给我每个不同的error_messages

的数量
=> {
 {"api_failure_1"=> "API failure 1",
  "api_failure_2"=> "API failure 2"}=>1,
 {"api_failure_1"=> "API failure 1",
  "api_failure_3"=> "API failure 3"}=>1
}

而不是其中每个键的计数。

我正在使用Rails 5.2和PostgreSQL 10.4

非常感谢任何指针或帮助。

2 个答案:

答案 0 :(得分:3)

事实上,您能够使它工作!进行以下查询:

query = <<-SQL 
  select errors.types, COUNT(errors.types)
  from (select jsonb_object_keys(error_messages) as types from api_responses) errors
  group by errors.types
SQL

your_result = API::Response.find_by_sql(query)

我仍然建议您创建一个视图,这样可以更轻松地访问它。

答案 1 :(得分:0)

我认为PostgreSQL无法对jsonb字段中的键进行分组。我认为您需要采取的方法:查询所有带有错误的响应,然后对所有找到的记录使用循环,以使用常规Ruby代码进行分组。

# not tested, but something like:
errors = API::Response.where.not("error_messages = '{}'").pluck(:error_messages)
error_holder = []
errors.each do |error|
  error_holder << error.keys
end
counts = Hash.new(0)
error_holder.flatten.each { |name| counts[name] += 1 }
puts counts