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)