31

I have a column in jsonb storing a map, like {'a':1,'b':2,'c':3} where the number of keys is different in each row.

I want to count it -- jsonb_object_keys can retrieve the keys but it is in setof

Are there something like this?

(select count(jsonb_object_keys(obj) from XXX )

(this won't work as ERROR: set-valued function called in context that cannot accept a set)

Postgres JSON Functions and Operators Document

json_object_keys(json)
jsonb_object_keys(jsonb)

setof text  Returns set of keys in the outermost JSON object.
json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}')  

json_object_keys
------------------
f1
f2

Crosstab isn't feasible as the number of key could be large.

5 Answers 5

38

Shortest:

SELECT count(*) FROM jsonb_object_keys('{"a": 1, "b": 2, "c": 3}'::jsonb);

Returns 3

If you want all json number of keys from a table, it gives:

SELECT (SELECT COUNT(*) FROM jsonb_object_keys(myJsonField)) nbr_keys FROM myTable;

Edit: there was a typo in the second example.

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

3 Comments

I'm getting function json_object_keys(character varying) does not exist Hint: No function matches the given name and argument types. You may need to add explicit type casts.;
@ericn I used pg v12 i think, which version do you use?
@ericn Do "select version();" on Amazon Redshift to get PG version. In the doc they say it doesn't support all 9.x feature and Json implementation is one of them. Ref: docs.aws.amazon.com/redshift/latest/dg/r_VERSION.html
14

You could convert keys to array and use array_length to get this:

select array_length(array_agg(A.key), 1) from (
    select json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}') as key
) A;

If you need to get this for the whole table, you can just group by primary key.

1 Comment

I'm getting function json_object_keys(character varying) does not exist Hint: No function matches the given name and argument types. You may need to add explicit type casts.;
5

Alternately, you could simply return the upper bounds of the keys when listed as an array:

SELECT
    ARRAY_UPPER( -- Grab the upper bounds of the array
        ARRAY( -- Convert rows into an array.
            SELECT JSONB_OBJECT_KEYS(obj)
        ),
        1 -- The array's dimension we're interested in retrieving the count for
    ) AS count
FROM
    xxx

Using '{"a": 1, "b": 2, "c": 3}'::jsonb as obj, count would result in a value of three (3).

Pasteable example:

SELECT
    ARRAY_UPPER( -- Grab the upper bounds of the array
        ARRAY( -- Convert rows into an array.
             SELECT JSONB_OBJECT_KEYS('{"a": 1, "b": 2, "c": 3}'::jsonb)
        ),
        1 -- The array's dimension we're interested in retrieving the count for
    ) AS count

Comments

5

While a sub select must be used to convert the JSON keys set to rows, the following tweaked query might run faster by skipping building the temporary array:

SELECT count(*) FROM
   (SELECT jsonb_object_keys('{"a": 1, "b": 2, "c": 3}'::jsonb)) v;

and it's a bit shorter ;)

To make it a function:

CREATE OR REPLACE FUNCTION public.count_jsonb_keys(j jsonb)
  RETURNS bigint
  LANGUAGE sql
AS $function$
SELECT count(*) from (SELECT jsonb_object_keys(j)) v;
$function$

Comments

0

To simplify the effort, you can define a function as follows:

CREATE OR REPLACE FUNCTION json_map_length(json) RETURNS integer AS
$$ SELECT array_length(array_agg(A.key), 1) FROM (
  SELECT json_object_keys($1) as key
) A; $$
LANGUAGE sql IMMUTABLE;

Comments

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.