Reference: JSON Functions
The following functions allow working with embedded json and jsonb documents.
create table json_data(data jsonb); -- json behaves similar, but is stored in plain text
insert into json_data
values ('{"id":1, "name": "philipp", "friends": [2, 3]}'),
('{"id":2, "name": "max", "friends": [1]}'),
('{"id":3, "name": "moritz", "friends": [1, 4]}'),
('{"id":4, "name": "christian", "friends": [3], "nick": "chris"}');Dictionary Access
The -> operator retrieves the json element with the specified string key from a JSON dictionary.
When the key is not found, it returns null.
select data->'name' from json_data; name
-------------
"philipp"
"max"
"moritz"
"christian"
(4 rows)Note the double quotes (") around the printed values.
This indicates that the results are JSON strings, not text columns.
Array Access
The -> also retrieves the json element with the specified integer index from a JSON array.
It returns null for out-of-bounds access.
select data->'friends'->0 from json_data; 0
---
2
1
1
3
(4 rows)Text Access
The ->> operator is similar to ->, but retrieves text columns instead of json columns.
This converts any value, especially JSON strings, but also integers and nested objects, to a text representation.
select data->>'name' from json_data; name
---------
philipp
max
moritz
christian
(4 rows)Conversions
Json and jsonb columns can be converted to and from text using standard conversion functions.
select data::text from json_data limit 1; text
-------------------------------------------------
{"id": 1, "name": "philipp", "friends": [2, 3]}
(1 row)For jsonb columns, CedarDB stores semantically equivalent documents, so you might get a syntactically different
text representation in a text::jsonb::text conversion.
In contrast, json columns are stored in a plain text representation, where such a conversion is character-by-character
equivalent, but the access operations are slower, since they need to re-parse the JSON string.
Arrays
The json_array_length() function allows calculating the number of elements in a JSON array:
select json_array_length(data->'friends') from json_data; json_array_length
-------------------
2
1
2
1
(4 rows)JSON arrays can sometimes be hard to work with in SQL, since they are not in a normalized relational model.
To relationalize arrays, you can use the json_array_elements() function, which transforms a row with a JSON array to
multiple rows with the elements of the array.
This is similar to the unnest() function for SQL arrays.
For the example, you can get a friends_with relation from the json array:
select data->'id', json_array_elements(data->'friends')
from json_data; id | json_array_elements
----+---------------------
3 | 1
3 | 4
1 | 2
1 | 3
4 | 3
2 | 1
(6 rows)Containment and Existence
The jsonb_contains function answers whether a given jsonb document is structurally contained within another jsonb document.
For example, the following query finds the name of the people that consider Max as a friend.
select data->'name' from json_data where jsonb_contains(data, '{"friends": [2]}'); name
-----------
"philipp"
(1 row)The @> operator performs the same operation when applied to json data.
The jsonb_exists function and the equivalent ? operator can determine if a given jsonb document has a given text as an object key or as an array value.
select data->'name', data->'nick' from json_data where data ? 'nick'; name | nick
-------------+---------
"christian" | "chris"
(1 row)Additionally, CedarDB supports the jsonb_exists_all (?& operator) and jsonb_exists_any (?|) variants, which check for the existence of all (or any) of a given set of keys.
select data->'name', data->'nick' from json_data
where jsonb_exists_any(data, ARRAY['nick', 'name']); name | nick
-------------+---------
"philipp" |
"max" |
"moritz" |
"christian" | "chris"
(4 rows)select data->'name', data->'nick' from json_data
where jsonb_exists_all(data, ARRAY['nick', 'name']); name | nick
-------------+---------
"christian" | "chris"
(1 rows)For the full semantics, refer to the PostgreSQL documentation: PostgreSQL JSONB containment and existence
Concatenation
The jsonb_concat operation concatenates two jsonb documents. To use it, call the jsonb_concat function or by providing jsonb as input to the || operator.
select data || '{"country": "Germany"}' from jsonb_data. ?column?
---------------------------------------------------------------------------------------
{"id": 1, "name": "philipp", "country": "Germany", "friends": [2, 3]}
{"id": 2, "name": "max", "country": "Germany", "friends": [1]}
{"id": 3, "name": "moritz", "country": "Germany", "friends": [1, 4]}
{"id": 4, "name": "christian", "nick": "chris", "country": "Germany", "friends": [3]}
(4 rows)select (data->'friends') || (data->>'id')::jsonb as me_and_my_friends from json_data; me_and_my_friends
-------------------
[2, 3, 1]
[1, 2]
[1, 4, 3]
[3, 4]
(4 rows)