How do I check if a json key exists in Postgres?
Asked Answered
F

6

102

Let's say I have a json that looks like this:

some_json = {'key_a': {'nested_key': 'a'},
             'key_b': {'nested_key': 'b'}}

Note that key_a and key_b are optional keys mapped to dictionaries and may or may not exist.

I have a function that checks if an outer key exists in some_json and returns a boolean.

CREATE FUNCTION key_exists(some_json json, outer_key text)
RETURNS boolean AS $$
BEGIN
    RETURN (some_json->outer_key IS NULL);
END;
$$ LANGUAGE plpgsql;

I get the following error:

ProgrammingError: operator does not exist: json -> boolean

Why is outer_key equating to a boolean? What's the proper syntax to perform this check?

Frosty answered 7/3, 2015 at 23:35 Comment(0)
I
51

Your function does the exact opposite of what the name is, but the way to fix your function is to add ( and ) around the some_json->outer_key.

Here is it fully functioning, and matching the name of your function (notice the NOT in front of the NULL).

CREATE FUNCTION key_exists(some_json json, outer_key text)
RETURNS boolean AS $$
BEGIN
    RETURN (some_json->outer_key) IS NOT NULL;
END;
$$ LANGUAGE plpgsql;

Some tests:

select key_exists('{"key_a": {"nested_key": "a"}, "key_b": {"nested_key": "b"}}'::json, 'key_a');
 key_exists 
------------
 t
(1 row)

And here when a key doesn't exist:

select key_exists('{"key_a": {"nested_key": "a"}, "key_b": {"nested_key": "b"}}'::json, 'test');
 key_exists 
------------
 f
(1 row)
Interlunar answered 8/3, 2015 at 0:36 Comment(1)
Got it working, thanks! Such a simple fix yet easy to overlook. Also good catch on the name.Frosty
G
164

You can also use the '?' operator like that:

SELECT '{"key_a":1}'::jsonb ? 'key_a'

And if you need to query by nested key, use like this:

SELECT '{"key_a": {"nested_key": "a"}}'::jsonb -> 'key_a' ? 'nested_key' 

See http://www.postgresql.org/docs/9.5/static/functions-json.html

NOTE: Only for jsonb type.

Geodetic answered 10/11, 2015 at 13:34 Comment(2)
Note when using this in a service that prepares the SQL statements (e.g. Metabase), it won't work, but you might be able to use ?? instead of ?.Buskirk
This seems like a much better answer, given a key that has a value of null will come back as true, which is expected.Shaun
I
51

Your function does the exact opposite of what the name is, but the way to fix your function is to add ( and ) around the some_json->outer_key.

Here is it fully functioning, and matching the name of your function (notice the NOT in front of the NULL).

CREATE FUNCTION key_exists(some_json json, outer_key text)
RETURNS boolean AS $$
BEGIN
    RETURN (some_json->outer_key) IS NOT NULL;
END;
$$ LANGUAGE plpgsql;

Some tests:

select key_exists('{"key_a": {"nested_key": "a"}, "key_b": {"nested_key": "b"}}'::json, 'key_a');
 key_exists 
------------
 t
(1 row)

And here when a key doesn't exist:

select key_exists('{"key_a": {"nested_key": "a"}, "key_b": {"nested_key": "b"}}'::json, 'test');
 key_exists 
------------
 f
(1 row)
Interlunar answered 8/3, 2015 at 0:36 Comment(1)
Got it working, thanks! Such a simple fix yet easy to overlook. Also good catch on the name.Frosty
P
6

PostgreSQL 14 add subscripting feature for json/jsonb.

SELECT ('{"key_a":1}'::jsonb) ['key_a'] is not null;

return t.

Panthea answered 22/3, 2022 at 16:28 Comment(0)
F
4

To check key exists or not you can use the operator -> this is used to get Get JSON object field by key For example:

actual json data in column(attribute): {
    "active": "t",
    "email_address": "[email protected]",
    "pin": "2233"
}

SELECT attributes::json->'email_address'
FROM entity
WHERE entity_id = 55;

You can also search key via operator #> and #>>

Get JSON object field as text: '{"a":1,"b":2}'::json->>'b' by using the operator ->>

Flareup answered 16/8, 2018 at 15:45 Comment(0)
R
4

If you want to select all rows where jsonb key exists you can just use such query:

SELECT * FROM my_table WHERE my_jsonb_field->'my_key' is not null
Rolo answered 1/3 at 17:43 Comment(0)
G
3

In Postgres, if you select a key that does not exist it will return null. so u can check the existence of a key by checking the null value of that key.

select '{"key_a": {"nested_key": "a"},
    "key_b": {"nested_key": "b"}}'::jsonb->>'a'
------------
null
(1 row)
Gillan answered 27/1, 2021 at 10:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.