JSON data types operators

Learn about the operators available for use with the json and jsonb data types.

There are parallel variants of the operators for both the json and jsonb types. The field/element/path extraction operators return the same type as their left input (either json or jsonb), except for those operators specified as returning text, which coerce the value to text. The field/element/path extraction operators return NULL, rather than failing, if the JSON input does not have the right structure to match the request; for example, if no such element exists. The field/element/path extraction operators that accept integer JSON array subscripts all support negative subscripting from the end of arrays.

Note: The #> and #>> operators use JSONB arrays as their right operand.

Operators available for json and jsonb

->
Right operand type: int
Get JSON array element (indexed from zero, negative integers count from the end).
Examples:
  • SELECT '["football", "volleyball", "soccer"]'::JSONB -> 0;
      ?COLUMN?  
    ------------
     "football"
    (1 row)
  • SELECT '["football", "volleyball", "soccer"]'::JSONB -> -1;
     ?COLUMN? 
    ----------
     "soccer"
    (1 row)
->
Right operand type: text
Get JSON object filed by key.
Examples:
  • SELECT '{"name": "Joe Smith", "age": 28}'::JSONB -> 'name';
      ?COLUMN?   
    -------------
     "Joe Smith"
    (1 row)
  • SELECT '{"name": "Joe Smith", "age": 28}'::JSONB -> 'age';
     ?COLUMN? 
    ----------
     28
    (1 row)
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football", "volleyball", "soccer"]}'::JSONB -> 'sports' -> 0;
      ?COLUMN?  
    ------------
     "football"
    (1 row)
->>
Right operand type: int
Get JSON array element as nvarchar.
Examples:
  • SELECT '["football", "volleyball", "soccer"]'::JSONB ->> 0;
     ?COLUMN? 
    ----------
     football
    (1 row)
  • SELECT '["football", "volleyball", "soccer"]'::JSONB ->> -1;
     ?COLUMN? 
    ----------
     soccer
    (1 row)
->>
Right operand type: text
Get JSON object field as nvarchar.
Examples:
  • SELECT '{"name": "Joe Smith", "age": 28}'::JSONB ->> 'name';
     ?COLUMN?  
    -----------
     Joe Smith
    (1 row)
  • SELECT '{"name": "Joe Smith", "age": 28}'::JSONB ->> 'age';
     ?COLUMN? 
    ----------
     28
    (1 row)
    
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football", "volleyball", "soccer"]}'::JSONB -> 'sports' ->> 0;
     ?COLUMN? 
    ----------
     football
    (1 row)
#>
Right operand type: JSONB arrays
Function: json_extract_path, jsonb_extract_path
Get JSON object at specified path.
Examples:
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football", "volleyball", "soccer"]}'::JSONB #> '["sports", 0]';
      ?COLUMN?  
    ------------
     "football"
    (1 row)
#>>
Right operand type: JSONB arrays
Function name: json_extract_path_text, jsonb_extract_path_text
Get JSON object at specified path as nvarchar.
Examples:
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football", "volleyball", "soccer"]}'::JSONB #>> '["sports", 0]';
     ?COLUMN? 
    ----------
     football
    (1 row)

Some further operators also exist only for jsonb, as described in the next section of this document.

Operators available for jsonb

Note: Some NPS drivers do not support operators with a question mark in them. Instead, you have to use the function. Also, the ?| and ?& operators use JSONB arrays as their right operand type.
?
Right operand type: text
Function name: jsonb_exists
Does the string exist as a top-level key within the JSON value?
Examples:
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football"]}'::JSONB ? 'age';
     ?COLUMN? 
    ----------
     t
    (1 row)
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football"]}'::JSONB ? 'address';
     ?COLUMN? 
    ----------
     f
    (1 row)
  • SELECT '{"n":null,"a":1,"b":[1,2],"c":{"1":2},"d":{"1":[2,3]},"一":"二"}'::jsonb ? 'e';
     ?COLUMN? 
    ----------
     f
    (1 row)
  • SELECT jsonb_exists('{"一":"null", "二":"qq"}', '三');
     JSONB_EXISTS 
    --------------
     f
    (1 row)
Tip: Question marks (?) are used as parameter place holders in ODBC and OLEDB drivers. You must use jsonb_exists() to check for the existence of a key:
Examples:
  • SELECT jsonb_exists('{"name": "Joe Smith", "age": 28, "sports": ["football"]}', 'age');
     JSONB_EXISTS 
    --------------
     t
    (1 row)
    
  • SELECT jsonb_exists('{"name": "Joe Smith", "age": 28, "sports": ["football"]}', 'address');
     JSONB_EXISTS 
    --------------
     f
    (1 row)
?|
Right operand type: JSONB arrays
Function: jsonb_exists_any

See also Overload functions.

Do any of these array strings exist as top-level keys?
Examples:
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football"]}'::JSONB ?| '["age", "address"]';
     ?COLUMN? 
    ----------
     t
    (1 row)
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football"]}'::JSONB ?| '["mobile", "address"]';
     ?COLUMN? 
    ----------
     f
    (1 row)
    Tip: Question marks (?) are used as parameter place holders in ODBC and OLEDB drivers. You must use jsonb_exists_any() to check for the existence of a key:
    Examples:
    • SELECT jsonb_exists_any('{"name": "Joe Smith", "age": 28, "sports": ["football"]}', '["age", "address"]');
       JSONB_EXISTS_ANY 
      ------------------
       t
      (1 row)
    • SELECT jsonb_exists_any('{"name": "Joe Smith", "age": 28, "sports": ["football"]}', '["mobile", "address"]');
       JSONB_EXISTS_ANY 
      ------------------
       f
      (1 row)
?&
Right operand type: JSONB arrays
Function: jsonb_exists_all

See also Overload functions.

Do all of these array strings exist as top-level keys?
Examples:
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football"]}'::JSONB ?& '["age", "address"]';
     ?COLUMN? 
    ----------
     f
    (1 row)
  • SELECT '{"name": "Joe Smith", "age": 28, "sports": ["football"]}'::JSONB ?& '["age", "sports"]';
     ?COLUMN? 
    ----------
     t
    (1 row)
    Tip: Question marks (?) are used as parameter place holders in ODBC and OLEDB drivers. You must use jsonb_exists_all() to check for the existence of a key:
    Examples:
    • SELECT jsonb_exists_all('{"name": "Joe Smith", "age": 28, "sports": ["football"]}', '["age", "address"]');
       JSONB_EXISTS_ALL 
      ------------------
       f
      (1 row)
    • SELECT jsonb_exists_all('{"name": "Joe Smith", "age": 28, "sports": ["football"]}', '["age", "sports"]');
       JSONB_EXISTS_ALL 
      ------------------
       t
      (1 row)
@?
Right operand type: jsonpath
Function: jsonb_path_exists()
Returns true if jsonpath returns at least one item for the specified jsonb value.
Examples:
  • SELECT '2'                @? '$ > 1'::JSONPATH;
     ?COLUMN? 
    ----------
     t
    (1 row)
  • select jsonb '{"a": 12}' @? '1';
     ?COLUMN? 
    ----------
     t
    (1 row)
  • select jsonb '["1",2,0,3]' @? '-$[*]';
     ?COLUMN? 
    ----------
     t
    (1 row)
@@
Right operand type: jsonpath
Function: jsonb_path_match
Returns the result of JSON path predicate check for the specified JSON value. Only the first item of the result is taken into account. If the result is not Boolean, then null is returned
Examples:
  • SELECT '2'::NCHAR(100)    @@ '$ > 1'::JSONPATH;
     ?COLUMN? 
    ----------
     t
    (1 row)
  • SELECT '2'::JSONB @@ '$ > 1'::JSONPATH;
     ?COLUMN? 
    ----------
     t
    (1 row)
  • SELECT '2'::JSONB @@ '1'::INT;
    ERROR:  Cannot convert 'INT4' to 'JSONB'
    SELECT '2'::JSONB @@ '1'::JSONB;
    ERROR:  Unable to identify an operator '@@' for types 'JSONB' and 'JSONB'
    	You will have to retype this query using an explicit cast
    SELECT '2'::JSONB @@ 'true'::BOOL ;
    ERROR:  Cannot convert 'BOOL' to 'JSONB'
The @? and @@ operators suppress:
  • Lacking object field or array element error.
  • Unexpected JSON item type, and numeric errors.
This might help if you're searching over JSON document collections of varying structure.

Containment and existence

Containment

Testing containment is an important capability of the jsonb data type. The json type doesn't have a parallel set of such facilities. Containment tests if a jsonb document has another document contained within it.

The contained object must match the containing object as to structure and data contents, possibly after discarding some non-matching array elements or object key/value pairs from the containing object. The order of array elements is not significant when carrying out a containment match, and duplicate array elements are effectively considered only once.

Examples:
  • Simple scalar/primitive values contain only the identical value:
    SELECT '"foo"'::jsonb @> '"foo"'::jsonb;
    ?COLUMN? 
    ----------
     t
    (1 row)
  • The array on the right side is contained within the one on the left:
    SELECT '[1, 2, 3]'::jsonb @> '[1, 3]'::jsonb;
    ?COLUMN? 
    ----------
     t
    (1 row)
  • Order of array elements is not significant, so this is also true:
    SELECT '[1, 2, 3]'::jsonb @> '[3, 1]'::jsonb;
    ?COLUMN? 
    ----------
     t
    (1 row)
  • Duplicate array elements don't matter either:
    SELECT '[1, 2, 3]'::jsonb @> '[1, 2, 2]'::jsonb;
    ?COLUMN? 
    ----------
     t
    (1 row)
  • The object with a single pair on the right side is contained within the object on the left side:
    SELECT '{"product": "PostgreSQL", "version": 9.4, "jsonb": true}'::jsonb @> '{"version": 9.4}'::jsonb;
    ?COLUMN? 
    ----------
     t
    (1 row)
  • The array on the right side is not considered contained within the array on the left, even though a similar array is nested within it:
    SELECT '[1, 2, [1, 3]]'::jsonb @> '[1, 3]'::jsonb;
    ?COLUMN? 
    ----------
     f
    (1 row)
    But with a layer of nesting, it is contained:
    SELECT '[1, 2, [1, 3]]'::jsonb @> '[[1, 3]]'::jsonb;
    ?COLUMN? 
    ----------
     t
    (1 row)
    Similarly, containment is not reported here:
    SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"bar": "baz"}'::jsonb;
    ?COLUMN? 
    ----------
     f
    (1 row)
  • A top-level key and an empty object is contained:
    SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"foo": {}}'::jsonb;
    ?COLUMN? 
    ----------
     t
    (1 row)

An array may contain a primitive value, which is an exception to the principle that the structures must match.

Example:
SELECT '["foo", "bar"]'::jsonb @> '"bar"'::jsonb;
?COLUMN? 
----------
 t
(1 row)
This exception is not reciprocal; non-containment is reported here:
SELECT '"bar"'::jsonb @> '["bar"]'::jsonb;
?COLUMN? 
----------
 f
(1 row)

Existence

jsonb also has an existence operator. It tests if a string (given as a text value) appears as an object key or an array element at the top level of the jsonb value. JSON objects are better suited than arrays for testing containment or existence when there are many keys or elements involved. Unlike arrays, they are internally optimized for searching, and do not need to be searched linearly.

Examples:
  • String exists as array element:
    SELECT '["foo", "bar", "baz"]'::jsonb ? 'bar';
    ?COLUMN? 
    ----------
     t
    (1 row)
  • String exists as object key:
    SELECT '{"foo": "bar"}'::jsonb ? 'foo';
    ?COLUMN? 
    ----------
     t
    (1 row)
  • Object values are not considered:
    SELECT '{"foo": "bar"}'::jsonb ? 'bar';
    ?COLUMN? 
    ----------
     f
    (1 row)
  • As with containment, existence must match at the top level:
    SELECT '{"foo": {"bar": "baz"}}'::jsonb ? 'bar';
    ?COLUMN? 
    ----------
     f
    (1 row)
  • A string is considered to exist if it matches a primitive JSON string:
    SELECT '"foo"'::jsonb ? 'foo';
    ?COLUMN? 
    ----------
     t
    (1 row)