3

I have a json column with entries that look like this:

{
  "pages": "64",
  "stats": {
    "1": { "200": "55", "400": "4" },
    "2": { "200": "1" },
    "3": { "200": "1", "404": "13" },
  }
}

The 'stats' are collections (of various sizes) containing http status codes versus counts.

I would like to aggregate the stats into two calculated columns - one for the total number of 200 responses and the other for the total number of responses (including 200s).

1 Answer 1

2

You can use two lateral joins to unnest the inner objects, then do conditional aggregation:

select 
    sum(z.cnt::int) no_responses,
    sum(z.cnt::int) filter(where z.code::int = 200) no_200_responses
from mytable t
cross join lateral jsonb_each(t.data -> 'stats') as x(kx, obj)
cross join lateral jsonb_each_text(x.obj) as z(code, cnt)

Demo on DB Fiddle:

no_responses | no_200_responses
-----------: | ---------------:
          74 |               57
Sign up to request clarification or add additional context in comments.

3 Comments

that's really close - thanks! - but I don't need to aggregate the results for all rows, I need the totals for each row as a calculated column
@WillJenkins: ok, I was wondering. If the primary key of your table is id, then you just need to group by id at the end of the query (you might also want to add this column to the select list).
boom! that's it, nice one

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.