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

Rails PostgreSQL jsonb GROUP BY query on internal dynamic keys

我有一个 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>

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

所以有些像:

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

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

我尝试做类似

的事情
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

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

我认为 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

事实上...您可以让它发挥作用!执行以下查询:

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)

我仍然建议创建一个视图,这样访问它会容易得多。