PolarDB for Oracle supports json and jsonb data types with a comprehensive set of operators and functions for querying and manipulating JSON data. This page covers:
Operators for json and jsonb
The following operators work with both json and jsonb values. Standard comparison operators (=, <, >, etc.) are also available for jsonb but not for json. These comparison operators follow B-tree ordering rules.
Operators shared by json and jsonb
| Operator | Description | Example | Result |
|---|---|---|---|
json -> integer → json<br>jsonb -> integer → jsonb | Extracts the nth element of a JSON array. Array elements are indexed from zero; negative integers count from the end. | '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> 2<br>'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> -3 | {"c":"baz"}<br>{"a":"foo"} |
json -> text → json<br>jsonb -> text → jsonb | Extracts a JSON object field by key. | '{"a": {"b":"foo"}}'::json -> 'a' | {"b":"foo"} |
json ->> integer → text<br>jsonb ->> integer → text | Extracts the nth element of a JSON array as text. | '[1,2,3]'::json ->> 2 | 3 |
json ->> text → text<br>jsonb ->> text → text | Extracts a JSON object field by key as text. | '{"a":1,"b":2}'::json ->> 'b' | 2 |
json #> text[] → json<br>jsonb #> text[] → jsonb | Extracts a JSON sub-object at the specified path. Path elements can be field keys or array indexes. | '{"a": {"b": ["foo","bar"]}}'::json #> '{a,b,1}' | "bar" |
json #>> text[] → text<br>jsonb #>> text[] → text | Extracts a JSON sub-object at the specified path as text. | '{"a": {"b": ["foo","bar"]}}'::json #>> '{a,b,1}' | bar |
Field, element, and path extraction operators return NULL rather than failing when the JSON input does not match the requested structure — for example, when the key or array element does not exist.
Additional operators for jsonb only
| Operator | Description | Example | Result | ||
|---|---|---|---|---|---|
jsonb @> jsonb → boolean | Does the first JSON value contain the second? | '{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb | t | ||
jsonb <@ jsonb → boolean | Is the first JSON value contained in the second? | '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb | t | ||
jsonb ? text → boolean | Does the text string exist as a top-level key or array element? | '{"a":1, "b":2}'::jsonb ? 'b' | t | ||
| `jsonb ? | text[] → boolean` | Do any of the strings in the text array exist as top-level keys or array elements? | `'{"a":1, "b":2, "c":3}'::jsonb ? | array['b', 'd']` | t |
jsonb ?& text[] → boolean | Do all of the strings in the text array exist as top-level keys or array elements? | '["a", "b", "c"]'::jsonb ?& array['a', 'b'] | t | ||
jsonb || jsonb → jsonb | Concatenates two jsonb values. Two arrays produce an array containing all elements from both inputs. Two objects produce an object with the union of their keys; the second object's value wins on duplicate keys. Non-array inputs are converted to single-element arrays before concatenation. Only the top-level structure is merged — concatenation is not recursive. To append an array as a single entry inside another array, wrap it in an additional array layer: '[1, 2]'::jsonb || jsonb_build_array('[3, 4]'::jsonb) → [1, 2, [3, 4]] | '["a", "b"]'::jsonb || '["a", "d"]'::jsonb<br>'{"a": "b"}'::jsonb || '{"c": "d"}'::jsonb<br>'[1, 2]'::jsonb || '3'::jsonb<br>'{"a": "b"}'::jsonb || '42'::jsonb | ["a", "b", "a", "d"]<br>{"a": "b", "c": "d"}<br>[1, 2, 3]<br>[{"a": "b"}, 42] | ||
jsonb - text → jsonb | Deletes a key (and its value) from a JSON object, or all matching string values from a JSON array. | '{"a": "b", "c": "d"}'::jsonb - 'a' | {"c": "d"} | ||
jsonb - text[] → jsonb | Deletes all matching keys or array elements from the left operand. | '{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[] | {} | ||
jsonb - integer → jsonb | Deletes the array element at the specified index. Negative integers count from the end. Throws an error if the JSON value is not an array. | '["a", "b"]'::jsonb - 1 | ["a"] | ||
jsonb #- text[] → jsonb | Deletes the field or array element at the specified path. Path elements can be field keys or array indexes. | '["a", {"b":1}]'::jsonb #- '{1,b}' | ["a", {}] | ||
jsonb @? jsonpath → boolean | Does the JSON path return any item for the specified JSON value? | '{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)' | t | ||
jsonb @@ jsonpath → boolean | Returns the result of a JSON path predicate check. Only the first item of the result is evaluated. Returns NULL if the result is not Boolean. | '{"a":[1,2,3,4,5]}'::jsonb @@ '$.a[*] > 2' | t |
The@?and@@operators suppress the following errors: missing object field or array element, unexpected JSON item type, and datetime and numeric errors. This behavior is useful when querying JSON document collections with varying structure.
JSON creation functions
The following functions construct json and jsonb values from SQL data.
to_json and to_jsonb
to_json ( anyelement ) → json
to_jsonb ( anyelement ) → jsonbConverts any SQL value to json or jsonb. Arrays and composites are converted recursively to JSON arrays and objects. If a cast from the SQL type to json exists, that cast function is used; otherwise, scalar values are represented as JSON strings (with escaping), booleans, numbers, or null as appropriate.
to_json('Fred said "Hi."'::text)
-- → "Fred said \"Hi.\""
to_jsonb(row(42, 'Fred said "Hi."'::text))
-- → {"f1": 42, "f2": "Fred said \"Hi.\""}array_to_json
array_to_json ( anyarray [, boolean ] ) → jsonConverts an SQL array to a JSON array. When the optional boolean parameter is true, line feeds are added between top-level array elements.
array_to_json('{{1,5},{99,100}}'::int[])
-- → [[1,5],[99,100]]row_to_json
row_to_json ( record [, boolean ] ) → jsonConverts an SQL composite value to a JSON object. When the optional boolean parameter is true, line feeds are added between top-level elements.
row_to_json(row(1,'foo'))
-- → {"f1":1,"f2":"foo"}json_build_array and jsonb_build_array
json_build_array ( VARIADIC "any" ) → json
jsonb_build_array ( VARIADIC "any" ) → jsonbBuilds a heterogeneously-typed JSON array from a variadic argument list. Each argument is converted using to_json or to_jsonb.
json_build_array(1, 2, 'foo', 4, 5)
-- → [1, 2, "foo", 4, 5]json_build_object and jsonb_build_object
json_build_object ( VARIADIC "any" ) → json
jsonb_build_object ( VARIADIC "any" ) → jsonbBuilds a JSON object from a variadic argument list of alternating keys and values. Key arguments are coerced to text; values are converted using to_json or to_jsonb.
json_build_object('foo', 1, 2, row(3,'bar'))
-- → {"foo" : 1, "2" : {"f1":3,"f2":"bar"}}json_object and jsonb_object
json_object ( text[] ) → json
jsonb_object ( text[] ) → jsonbBuilds a JSON object from a text array. The array must either have one dimension with an even number of members (treated as alternating key/value pairs), or two dimensions where each inner array has exactly two elements. All values are converted to JSON strings.
json_object('{a, 1, b, "def", c, 3.5}')
-- → {"a" : "1", "b" : "def", "c" : "3.5"}
json_object('{{a, 1}, {b, "def"}, {c, 3.5}}')
-- → {"a" : "1", "b" : "def", "c" : "3.5"}A two-argument form takes keys and values from separate text arrays:
json_object ( keys text[], values text[] ) → json
jsonb_object ( keys text[], values text[] ) → jsonbjson_object('{a,b}', '{1,2}')
-- → {"a": "1", "b": "2"}If an extension provides a cast from its type tojson(for example, thehstoreextension), values converted via these creation functions use that cast rather than being represented as primitive strings.
JSON processing functions
The following functions query and manipulate json and jsonb values.
Expanding and querying JSON
`json_array_elements` and `jsonb_array_elements`
json_array_elements ( json ) → setof json
jsonb_array_elements ( jsonb ) → setof jsonbExpands the top-level JSON array into a set of JSON values.
select * from json_array_elements('[1,true, [2,false]]');
-- value
-- -----------
-- 1
-- true
-- [2,false]`json_array_elements_text` and `jsonb_array_elements_text`
json_array_elements_text ( json ) → setof text
jsonb_array_elements_text ( jsonb ) → setof textExpands the top-level JSON array into a set of text values.
select * from json_array_elements_text('["foo", "bar"]');
-- value
-- -----------
-- foo
-- bar`json_array_length` and `jsonb_array_length`
json_array_length ( json ) → integer
jsonb_array_length ( jsonb ) → integerReturns the number of elements in the top-level JSON array.
json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]')
-- → 5`json_each` and `jsonb_each`
json_each ( json ) → setof record ( key text, value json )
jsonb_each ( jsonb ) → setof record ( key text, value jsonb )Expands the top-level JSON object into a set of key/value pairs.
select * from json_each('{"a":"foo", "b":"bar"}');
-- key | value
-- -----+-------
-- a | "foo"
-- b | "bar"`json_each_text` and `jsonb_each_text`
json_each_text ( json ) → setof record ( key text, value text )
jsonb_each_text ( jsonb ) → setof record ( key text, value text )Expands the top-level JSON object into a set of key/value pairs, with values returned as text.
select * from json_each_text('{"a":"foo", "b":"bar"}');
-- key | value
-- -----+-------
-- a | foo
-- b | bar`json_object_keys` and `jsonb_object_keys`
json_object_keys ( json ) → setof text
jsonb_object_keys ( jsonb ) → setof textReturns the set of keys in the top-level JSON object.
select * from json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}');
-- json_object_keys
-- ------------------
-- f1
-- f2Extracting sub-objects
`json_extract_path` and `jsonb_extract_path`
json_extract_path ( from_json json, VARIADIC path_elems text[] ) → json
jsonb_extract_path ( from_json jsonb, VARIADIC path_elems text[] ) → jsonbExtracts a JSON sub-object at the specified path. Equivalent to the #> operator, but writing the path as a variadic list can be more convenient in some cases.
json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6')
-- → "foo"`json_extract_path_text` and `jsonb_extract_path_text`
json_extract_path_text ( from_json json, VARIADIC path_elems text[] ) → text
jsonb_extract_path_text ( from_json jsonb, VARIADIC path_elems text[] ) → textExtracts a JSON sub-object at the specified path as text. Equivalent to the #>> operator.
json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6')
-- → fooPopulating composite types from JSON
`json_populate_record` and `jsonb_populate_record`
json_populate_record ( base anyelement, from_json json ) → anyelement
jsonb_populate_record ( base anyelement, from_json jsonb ) → anyelementExpands the top-level JSON object into a row matching the composite type of base. Fields whose names match output column names are inserted into those columns; unmatched fields are ignored. When base is NULL, unmatched columns are filled with nulls; otherwise, unmatched columns retain the values from base.
The following type conversion rules apply in order:
A JSON null converts to SQL NULL in all cases.
If the output column is of type
jsonorjsonb, the JSON value is reproduced exactly.If the output column is a composite (row) type and the JSON value is a JSON object, the fields are converted recursively.
If the output column is an array type and the JSON value is a JSON array, the elements are converted recursively.
If the JSON value is a string, its contents are passed to the input conversion function for the column's data type.
Otherwise, the text representation of the JSON value is passed to the input conversion function.
Use json_populate_record in the FROM clause to make all extracted columns available without duplicate function calls.
create type subrowtype as (d int, e text);
create type myrowtype as (a int, b text[], c subrowtype);
select * from json_populate_record(null::myrowtype,
'{"a": 1, "b": ["2", "a b"], "c": {"d": 4, "e": "a b c"}, "x": "foo"}');
-- a | b | c
-- ---+-----------+-------------
-- 1 | {2,"a b"} | (4,"a b c")`json_populate_recordset` and `jsonb_populate_recordset`
json_populate_recordset ( base anyelement, from_json json ) → setof anyelement
jsonb_populate_recordset ( base anyelement, from_json jsonb ) → setof anyelementExpands the top-level JSON array of objects into a set of rows matching the composite type of base. Each element is processed as described for json_populate_record.
create type twoints as (a int, b int);
select * from json_populate_recordset(null::twoints, '[{"a":1,"b":2}, {"a":3,"b":4}]');
-- a | b
-- ---+---
-- 1 | 2
-- 3 | 4`json_to_record` and `jsonb_to_record`
json_to_record ( json ) → record
jsonb_to_record ( jsonb ) → recordExpands the top-level JSON object into a row with the composite type defined by an AS clause. The calling query must explicitly define the record structure with an AS clause. Unmatched columns are always filled with nulls.
create type myrowtype as (a int, b text);
select * from json_to_record('{"a":1,"b":[1,2,3],"c":[1,2,3],"e":"bar","r": {"a": 123, "b": "a b c"}}')
as x(a int, b text, c int[], d text, r myrowtype);
-- a | b | c | d | r
-- ---+---------+---------+---+---------------
-- 1 | [1,2,3] | {1,2,3} | | (123,"a b c")`json_to_recordset` and `jsonb_to_recordset`
json_to_recordset ( json ) → setof record
jsonb_to_recordset ( jsonb ) → setof recordExpands the top-level JSON array of objects into a set of rows with the composite type defined by an AS clause. Each element is processed as described for json_to_record.
select * from json_to_recordset('[{"a":1,"b":"foo"}, {"a":"2","c":"bar"}]')
as x(a int, b text);
-- a | b
-- ---+-----
-- 1 | foo
-- 2 |Modifying JSON values
`jsonb_set`
jsonb_set ( target jsonb, path text[], new_value jsonb [, create_if_missing boolean ] ) → jsonbReturns target with the item at path replaced by new_value. When create_if_missing is true (the default) and the item at path does not exist, new_value is inserted instead. All earlier steps in the path must exist, or target is returned unchanged.
Negative integers in path count from the end of JSON arrays. If the last path step is an out-of-range array index and create_if_missing is true, the new value is added at the beginning of the array (for a negative index) or at the end (for a positive index).
jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', '[2,3,4]', false)
-- → [{"f1": [2, 3, 4], "f2": null}, 2, null, 3]
jsonb_set('[{"f1":1,"f2":null},2]', '{0,f3}', '[2,3,4]')
-- → [{"f1": 1, "f2": null, "f3": [2, 3, 4]}, 2]`jsonb_set_lax`
jsonb_set_lax ( target jsonb, path text[], new_value jsonb [, create_if_missing boolean [, null_value_treatment text ]] ) → jsonbWhen new_value is not NULL, behaves identically to jsonb_set. When new_value is NULL, the behavior depends on null_value_treatment:
| Value | Behavior |
|---|---|
'raise_exception' | Throws an error |
'use_json_null' | Sets the target to JSON null (default) |
'delete_key' | Deletes the key at the path |
'return_target' | Returns target unchanged |
jsonb_set_lax('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', null)
-- → [{"f1":null,"f2":null},2,null,3]
jsonb_set_lax('[{"f1":99,"f2":null},2]', '{0,f3}', null, true, 'return_target')
-- → [{"f1": 99, "f2": null}, 2]`jsonb_insert`
jsonb_insert ( target jsonb, path text[], new_value jsonb [, insert_after boolean ] ) → jsonbReturns target with new_value inserted at path. For array elements, new_value is inserted before the target element when insert_after is false (the default), or after it when true. For object fields, new_value is inserted only if the key does not already exist. All earlier steps in the path must exist, or target is returned unchanged.
Negative integers in path count from the end of JSON arrays. An out-of-range array index adds the value at the beginning (negative index) or the end (positive index) of the array.
jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"')
-- → {"a": [0, "new_value", 1, 2]}
jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"', true)
-- → {"a": [0, 1, "new_value", 2]}Cleaning and formatting
`json_strip_nulls` and `jsonb_strip_nulls`
json_strip_nulls ( json ) → json
jsonb_strip_nulls ( jsonb ) → jsonbRemoves all object fields with null values from the given JSON value, recursively. Null values that are not object fields (for example, null array elements) are left unchanged.
json_strip_nulls('[{"f1":1, "f2":null}, 2, null, 3]')
-- → [{"f1":1},2,null,3]`jsonb_pretty`
jsonb_pretty ( jsonb ) → textConverts the given JSON value to pretty-printed, indented text.
jsonb_pretty('[{"f1":1,"f2":null}, 2]')
-- → [
-- {
-- "f1": 1,
-- "f2": null
-- },
-- 2
-- ]`json_typeof` and `jsonb_typeof`
json_typeof ( json ) → text
jsonb_typeof ( jsonb ) → textReturns the type of the top-level JSON value as a text string. Possible types: object, array, string, number, boolean, and null.
Thenullresult reflects the JSON value null — not a SQL NULL. A SQL NULL input returns a SQL NULL result, not the string'null'.
json_typeof('-123.4') -- → number
json_typeof('null'::json) -- → null
json_typeof(NULL::json) IS NULL -- → tAggregate functions
json_agg aggregates record values into a JSON array. json_object_agg aggregates pairs of values into a JSON object. Their jsonb counterparts — jsonb_agg and jsonb_object_agg — produce jsonb output.
json_agg ( anyelement ) → json
jsonb_agg ( anyelement ) → jsonb
json_object_agg ( "any", "any" ) → json
jsonb_object_agg ( "any", "any" ) → jsonbJSON path functions
The following functions evaluate JSON path expressions against jsonb values.
All functions in this group accept the same optional parameters:
vars— a JSON object whose fields provide named values to substitute into thejsonpathexpressionsilent— whentrue, suppresses the same errors as the@?and@@operators
`jsonb_path_exists`
jsonb_path_exists ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → booleanChecks whether the JSON path returns any item for the specified JSON value.
jsonb_path_exists('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}')
-- → t`jsonb_path_match`
jsonb_path_match ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → booleanReturns the result of a JSON path predicate check. Only the first item of the result is evaluated. Returns NULL if the result is not Boolean.
jsonb_path_match('{"a":[1,2,3,4,5]}', 'exists($.a[*] ? (@ >= $min && @ <= $max))', '{"min":2, "max":4}')
-- → t`jsonb_path_query`
jsonb_path_query ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → setof jsonbReturns all JSON items returned by the JSON path for the specified JSON value.
select * from jsonb_path_query('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}');
-- jsonb_path_query
-- ------------------
-- 2
-- 3
-- 4`jsonb_path_query_array`
jsonb_path_query_array ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonbReturns all JSON items returned by the JSON path as a JSON array.
jsonb_path_query_array('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}')
-- → [2, 3, 4]`jsonb_path_query_first`
jsonb_path_query_first ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonbReturns the first JSON item returned by the JSON path. Returns NULL if there are no results.
jsonb_path_query_first('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}')
-- → 2Timezone-aware variants
The functions jsonb_path_exists_tz, jsonb_path_match_tz, jsonb_path_query_tz, jsonb_path_query_array_tz, and jsonb_path_query_first_tz work identically to their counterparts above, but support comparisons of date/time values that require timezone-aware conversions.
Because these functions depend on the current TimeZone setting, they are marked as stable and cannot be used in indexes. The non-_tz variants are immutable and can be used in indexes, but throw errors if asked to make timezone-dependent comparisons.
jsonb_path_exists_tz('["2015-08-01 12:00:00 -05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())')
-- → tThe SQL/JSON path language
The SQL/JSON path language specifies which items to retrieve from JSON data, similar to how XPath expressions work for XML. In PolarDB, path expressions are implemented as the jsonpath data type.
JSON query functions and operators pass the path expression to the path engine for evaluation. When the expression matches the queried JSON data, the corresponding JSON item or set of items is returned. Path expressions are evaluated from left to right by default; use parentheses to change the order of operations.
Navigating JSON with path expressions
Use the $ variable to refer to the JSON value being queried (the context item). Follow $ with one or more accessor operators to traverse the JSON structure.
For example, given this GPS tracker data:
{
"track": {
"segments": [
{
"location": [ 47.763, 13.4034 ],
"start time": "2018-10-14 10:05:14",
"HR": 73
},
{
"location": [ 47.706, 13.2635 ],
"start time": "2018-10-14 10:39:21",
"HR": 135
}
]
}
}Use the .key accessor to descend through JSON objects:
$.track.segmentsUse [*] to retrieve all elements of an array:
$.track.segments[*].locationUse a numeric subscript to access a specific element (JSON array indexes are zero-based):
$.track.segments[0].locationAppend a method call (preceded by a dot) to process the result of a path step:
$.track.segments.size()Filter expressions
Filter expressions narrow the results of a path step to only those items that satisfy a condition. Write a filter immediately after the path step it applies to:
? (condition)SQL/JSON uses three-valued logic: conditions evaluate to true, false, or unknown. Only items for which the filter returns true are included in subsequent path steps. Use the is unknown predicate to test for the unknown value.
Within a filter, @ refers to the value being filtered (the result of the preceding path step).
Examples using the GPS tracker data:
Retrieve all heart rate values above 130:
$.track.segments[*].HR ? (@ > 130)Get start times for segments with heart rate above 130 (the filter applies to the segment, not the HR value):
$.track.segments[*] ? (@.HR > 130)."start time"Chain multiple filters to select segments with relevant location coordinates and high heart rate:
$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time"Filter at different nesting levels — filter segments by location first, then return high heart rate values:
$.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130)Nest filter expressions to return the track size only if any segment has high heart rate values:
$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()Strict and lax modes
When a path expression does not match the actual JSON structure, a structural error occurs. SQL/JSON path expressions handle structural errors in two modes:
Lax (default): The path engine automatically adapts the queried data to the specified path. Remaining structural errors are suppressed and converted to empty SQL/JSON sequences. Comparison operators automatically unwrap their operands, so you can compare SQL/JSON arrays directly. An array of size 1 is considered equal to its sole element. Automatic unwrapping is not applied when the path contains
type()orsize()methods, or when the JSON data contains nested arrays (only the outermost array is unwrapped).Strict: An error is raised when a structural error occurs.
Using the GPS tracker data in lax mode, you can omit the explicit array unwrapping:
lax $.track.segments.locationIn strict mode, you must explicitly unwrap the array:
strict $.track.segments[*].locationDeviations from the SQL/JSON standard
PolarDB's implementation differs from the SQL/JSON standard in two ways:
A path expression can be a Boolean predicate, even though the standard allows predicates only in filters. This is required for the
@@operator. For example, the followingjsonpathexpression is valid:$.track.segments[*].HR < 70There are minor differences in how regular expression patterns are interpreted in
like_regexfilters.
SQL/JSON path operators and methods
All jsonpath operators and methods are listed below. Unary operators and methods can be applied to multiple values from a preceding path step; binary operators (addition, etc.) apply only to single values.
| Operator / Method | Returns | Description | Example | Result |
|---|---|---|---|---|
number + number | number | Addition | jsonb_path_query('[2]', '$[0] + 3') | 5 |
+ number | number | Unary plus (no-op); can iterate over multiple values | jsonb_path_query_array('{"x": [2,3,4]}', '+ $.x') | [2, 3, 4] |
number - number | number | Subtraction | jsonb_path_query('[2]', '7 - $[0]') | 5 |
- number | number | Negation; can iterate over multiple values | jsonb_path_query_array('{"x": [2,3,4]}', '- $.x') | [-2, -3, -4] |
number * number | number | Multiplication | jsonb_path_query('[4]', '2 * $[0]') | 8 |
number / number | number | Division | jsonb_path_query('[8.5]', '$[0] / 2') | 4.2500000000000000 |
number % number | number | Modulo | jsonb_path_query('[32]', '$[0] % 10') | 2 |
value .type() | string | Type of the JSON item (see json_typeof) | jsonb_path_query_array('[1, "2", {}]', '$[*].type()') | ["number", "string", "object"] |
value .size() | integer | Number of array elements; 1 for non-arrays | jsonb_path_query('{"m": [11, 15]}', '$.m.size()') | 2 |
value .double() | number | Approximate floating-point number converted from a JSON number or string | jsonb_path_query('{"len": "1.9"}', '$.len.double() * 2') | 3.8 |
number .ceiling() | integer | Nearest integer greater than or equal to the given number | jsonb_path_query('{"h": 1.3}', '$.h.ceiling()') | 2 |
number .floor() | integer | Nearest integer less than or equal to the given number | jsonb_path_query('{"h": 1.7}', '$.h.floor()') | 1 |
number .abs() | number | Absolute value | jsonb_path_query('{"z": -0.3}', '$.z.abs()') | 0.3 |
string .datetime() | datetime | Date/time value converted from a string, matched against ISO formats in order: date, timetz, time, timestamptz, timestamp | jsonb_path_query('["2015-8-1", "2015-08-12"]', '$[*] ? (@.datetime() < "2015-08-2".datetime()') | "2015-8-1" |
string .datetime(template) | datetime | Date/time value converted using the specified to_timestamp template | jsonb_path_query_array('["12:30", "18:40"]', '$[*].datetime("HH24:MI")') | ["12:30:00", "18:40:00"] |
object .keyvalue() | array | Key-value pairs as an array of objects with "key", "value", and "id" fields. "id" is a unique identifier for the source object. | jsonb_path_query_array('{"x": "20", "y": 32}', '$.keyvalue()') | [{"id": 0, "key": "x", "value": "20"}, {"id": 0, "key": "y", "value": 32}] |
Thedatetime()anddatetime(template)methods use the same parsing rules as theto_timestampSQL function, with three exceptions: unmatched template patterns are not allowed; only the following separators are valid in the template string:-,.,/,,,',;,:, and space; and separators in the template must exactly match the input string. When date/time types must be compared, an implicit cast is applied:datecan cast totimestamportimestamptz,timestampcan cast totimestamptz, andtimetotimetz. All casts except the first depend on the currentTimeZonesetting and can only be performed within timezone-awarejsonpathfunctions.
SQL/JSON filter expression elements
The following operators and predicates can be used inside filter expressions (? (condition)).
| Element | Returns | Description | Example | Result |
|---|---|---|---|---|
value == value | boolean | Equality comparison (works on all JSON scalar values) | jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == 1)') | [1, 1] |
value != value<br>value <> value | boolean | Non-equality comparison | jsonb_path_query_array('[1, 2, 1, 3]', '$[*] ? (@ != 1)') | [2, 3] |
value < value | boolean | Less-than comparison | jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ < 2)') | [1] |
value <= value | boolean | Less-than-or-equal-to comparison | jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <= "b")') | ["a", "b"] |
value > value | boolean | Greater-than comparison | jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ > 2)') | [3] |
value >= value | boolean | Greater-than-or-equal-to comparison | jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ >= 2)') | [2, 3] |
true | boolean | JSON constant true | jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == true)') | {"name": "Chris", "parent": true} |
false | boolean | JSON constant false | jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == false)') | {"name": "John", "parent": false} |
null | — | JSON constant null. Unlike SQL, comparison to null works normally in jsonpath. | jsonb_path_query('[{"name": "Mary", "job": null}, {"name": "Michael", "job": "driver"}]', '$[*] ? (@.job == null) .name') | "Mary" |
boolean && boolean | boolean | Boolean AND | jsonb_path_query('[1, 3, 7]', '$[*] ? (@ > 1 && @ < 5)') | 3 |
boolean || boolean | boolean | Boolean OR | jsonb_path_query('[1, 3, 7]', '$[*] ? (@ < 1 || @ > 5)') | 7 |
! boolean | boolean | Boolean NOT | jsonb_path_query('[1, 3, 7]', '$[*] ? (!(@ < 5))') | 7 |
boolean is unknown | boolean | Tests whether a Boolean condition is unknown | jsonb_path_query('[-1, 2, 7, "foo"]', '$[*] ? ((@ > 0) is unknown)') | "foo" |
string like_regex string [flag string] | boolean | Tests whether the first operand matches the regular expression given by the second operand. The optional flag string can include: i (case-insensitive), m (^ and $ match at newlines), s (. matches a newline), q (quote the whole pattern as a literal string). | jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c" flag "i")') | ["abc", "aBdC", "abdacb"] |
string starts with string | boolean | Tests whether the second operand is an initial substring of the first | jsonb_path_query('["John Smith", "Mary Stone", "Bob Johnson"]', '$[*] ? (@ starts with "John")') | "John Smith" |
exists (path_expression) | boolean | Tests whether a path expression matches at least one SQL/JSON item. Returns unknown if the path expression would produce an error, which avoids no-such-key errors in strict mode. | jsonb_path_query('{"x": [1, 2], "y": [2, 4]}', 'strict $.* ? (exists (@ ? (@[*] > 2)))') | [2, 4] |
SQL/JSON regular expressions
The like_regex filter matches text against a regular expression. For example, the following path query case-insensitively matches all strings in an array that start with an English vowel:
$[*] ? (@ like_regex "^[aeiou]" flag "i")The like_regex pattern is a JSON path string literal, so backslashes must be doubled. To match strings containing only digits:
$ ? (@ like_regex "^\\d+$")like_regex is implemented using the POSIX regular expression engine rather than the XQuery LIKE_REGEX operator defined in the SQL/JSON standard. This causes minor behavioral differences from the standard. Flag letters are translated to match what the POSIX engine expects.