2

I have an ActiveRecord model let's call it API::Response and within that we have column named error_messages which stores the error messages when the API call fails.

The structure of API::Response is something like:

#<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>

What I want to do is to get a result where I am grouping by keys within the error_messages column and get the count of occurrence each key:

so some something like:

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

where keys in the error_messages jsonb field are dynamic.

I tried to do something like

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

but this just gives me count of each distinct 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
}

rather then the count of each key within.

I am on Rails 5.2 and PostgreSQL 10.4

Any pointers or help is very much appreciated.

2 Answers 2

4

As a matter of fact... you are able to make it work! Do the following query:

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)

I'd still advise to create a View, that makes accessing it a lot easier.

Sign up to request clarification or add additional context in comments.

Comments

0

I don't think PostgreSQL is able to do groupings on keys in a jsonb field. The approach I think you need to do: query all responses with errors, then use a loop on all found records to group with normal Ruby code.

# 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

2 Comments

I was thinking of some similar but curious if we can do something on db level directly without loading the data in memory since the table is pretty big.
I create a new answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.