Chapter 15. JSON Types in MobilityDB

Table of Contents

JSONB Operations
JSONB Set Operations
Temporal JSONB values
Validity of temporal JSONB values
Input and Output
Constructors
Conversions
Accessors
Transformations
Temporal JSON Operations
Restrictions
Bounding Box Operations
Comparisons
Aggregations
Indexing

PostgreSQL provides two types for storing JSON data: json and jsonb. The json type stores an exact copy of the input text, which must be reparsed each time it is processed. On the other hand, the jsonb type stores the JSON data in a decomposed binary format that makes it slightly slower to input due to added conversion overhead, but significantly faster to process, since no reparsing is needed. The jsonb type also supports indexing.

In MobilityDB, the textset and the ttext types are used for representing, respectively, set of JSON values and temporal JSON values. Furthermore, the jsonb type serves as base type for defining the jsonbset and the tjsonb types. Most functions and operators described in the previous chapters for set and temporal types are also applicable for the corresponding JSON types. In addition, there are specific functions defined for these types, which are derived from the corresponding functions of the json and the jsonb types.

In this chapter, we describe the MobilityDB JSON types and its associated operations. We refer to the PostgreSQL documentation for a detailed explanation of the json and jsonb types and their functionality. We aimed at enabling the same syntax of the original PostgreSQL functions for the corresponding MobilityDB types, as illustrated in this document.

Consider for example the -> operator, which extracts a JSON object field with a given key.

SELECT jsonb '{"unit": "km", "speed": 10}' -> text 'speed';
-- 10

Applying the same operator to a JSONB set and to a temporal JSONB value yields the following results

SELECT jsonbset '{"{\"unit\": \"km\", \"speed\": 10}",
  "{\"unit\": \"km\", \"speed\": 20}"}' -> text 'speed';
-- {10, 20}
SELECT tjsonb '[{"unit": "km", "speed": 10}@2001-01-01,
  {"unit": "km", "speed": 20}@2001-01-02]' -> text 'speed';
-- {["10"@2001-01-01, "20"@2001-01-02]}

which are obtained by applying the PostgreSQL operator -> at every element of the JSONB set and to every instant of the temporal JSONB value.

JSONB Operations

PostgreSQL provides the following operations of JSONB values under its own names and operators. MobilityDB names them as their JSONB set and temporal JSONB counterparts, so that a query calling these names runs unchanged in every engine of the ecosystem (the section called “Base Values Provided by the Host”). The operators of PostgreSQL keep their symbols.

  • Extract a JSON object field specified by a key

    jsonbObjectField(jsonb,text) → jsonb
    jsonbObjectFieldText(jsonb,text) → text
    
    SELECT jsonbObjectField(jsonb '{"a": {"b": 1}}', 'a');
    -- {"b": 1}
    SELECT jsonbObjectFieldText(jsonb '{"a": "x"}', 'a');
    -- x
    
  • Extract a JSON value specified by a path

    jsonbExtractPath(jsonb,path text[]) → jsonb
    jsonbExtractPathText(jsonb,path text[]) → text
    
    SELECT jsonbExtractPath(jsonb '{"a": {"b": [10, 20]}}', ARRAY['a', 'b', '1']);
    -- 20
    SELECT jsonbExtractPathText(jsonb '{"a": {"b": "z"}}', ARRAY['a', 'b']);
    -- z
    
  • Extract an element from a JSON array

    jsonbArrayElement(jsonb,integer) → jsonb
    jsonbArrayElementText(jsonb,integer) → text
    

    Elements are numbered from zero, and a negative integer counts from the end of the array.

    SELECT jsonbArrayElement(jsonb '[1, [2, 3]]', 1);
    -- [2, 3]
    SELECT jsonbArrayElement(jsonb '[1, 2, 3]', -1);
    -- 3
    SELECT jsonbArrayElementText(jsonb '["x", "y"]', 0);
    -- x
    
  • Return the number of elements of a JSON array

    jsonbArrayLength(jsonb) → integer
    
    SELECT jsonbArrayLength(jsonb '[1, 2, 3]');
    -- 3
    
  • Return the elements of a JSON array as rows

    jsonbArrayElements(jsonb) → setof jsonb
    jsonbArrayElementsText(jsonb) → setof text
    
    SELECT * FROM jsonbArrayElements(jsonb '[1, "two", {"three": 3}]');
    -- 1
    -- "two"
    -- {"three": 3}
    SELECT * FROM jsonbArrayElementsText(jsonb '[1, "two"]');
    -- 1
    -- two
    
  • Return the fields of a JSON object as rows of a key and a value

    jsonbEach(jsonb) → setof (key text,value jsonb)
    jsonbEachText(jsonb) → setof (key text,value text)
    
    SELECT * FROM jsonbEach(jsonb '{"a": 1, "b": [2]}') ORDER BY key;
    -- a | 1
    -- b | [2]
    SELECT * FROM jsonbEachText(jsonb '{"a": 1, "b": "x"}') ORDER BY key;
    -- a | 1
    -- b | x
    
  • Return the keys of a JSON object as rows

    jsonbObjectKeys(jsonb) → setof text
    
    SELECT * FROM jsonbObjectKeys(jsonb '{"b": 1, "a": 2}') ORDER BY 1;
    -- a
    -- b
    
  • Return the indented text of a JSON value

    jsonbPretty(jsonb) → text
    
    SELECT jsonbPretty(jsonb '{"a": 1}');
    -- {
    --     "a": 1
    -- }
    
  • Concatenate two JSON values

    jsonbConcat(jsonb,jsonb) → jsonb
    
    SELECT jsonbConcat(jsonb '{"a": 1}', jsonb '{"b": 2}');
    -- {"a": 1, "b": 2}
    
  • Delete a key, the keys of an array, an array element or the item at a path from a JSON value

    jsonbDelete(jsonb,text) → jsonb
    jsonbDeleteArray(jsonb,text[]) → jsonb
    jsonbDeleteIndex(jsonb,integer) → jsonb
    jsonbDeletePath(jsonb,path text[]) → jsonb
    
    SELECT jsonbDelete(jsonb '{"a": 1, "b": 2}', 'a');
    -- {"b": 2}
    SELECT jsonbDeleteArray(jsonb '{"a": 1, "b": 2, "c": 3}', ARRAY['a', 'c']);
    -- {"b": 2}
    SELECT jsonbDeleteIndex(jsonb '[1, 2, 3]', -1);
    -- [1, 2]
    SELECT jsonbDeletePath(jsonb '{"a": {"b": 1, "c": 2}}', ARRAY['a', 'b']);
    -- {"a": {"c": 2}}
    
  • Does a text, or any or all the texts of an array, exist as a top-level key or array element of a JSON value?

    jsonbExists(jsonb,text) → boolean
    jsonbExistsAny(jsonb,text[]) → boolean
    jsonbExistsAll(jsonb,text[]) → boolean
    
    SELECT jsonbExists(jsonb '{"a": 1}', 'a');
    -- true
    SELECT jsonbExistsAny(jsonb '{"a": 1}', ARRAY['b', 'a']);
    -- true
    SELECT jsonbExistsAll(jsonb '{"a": 1}', ARRAY['b', 'a']);
    -- false
    
  • Does the first JSON value contain, or is it contained in, the second one?

    jsonbContains(jsonb,jsonb) → boolean
    jsonbContained(jsonb,jsonb) → boolean
    
    SELECT jsonbContains(jsonb '{"a": 1, "b": 2}', jsonb '{"a": 1}');
    -- true
    SELECT jsonbContained(jsonb '{"a": 1}', jsonb '{"a": 1, "b": 2}');
    -- true
    
  • Return a JSON value with the item at a path set to a value

    jsonbSet(jsonb,path text[],val jsonb,create_missing boolean=true) → jsonb
    jsonbSetLax(jsonb,path text[],val jsonb,create_missing boolean=true,
      handle_null text='use_json_null') → jsonb
    

    The item is added when it does not exist and create_missing is true. Function jsonbSetLax treats a NULL value according to handle_null, which is one of 'raise_exception', 'use_json_null', 'delete_key' or 'return_target'.

    SELECT jsonbSet(jsonb '{"a": 1}', ARRAY['b'], jsonb '2');
    -- {"a": 1, "b": 2}
    SELECT jsonbSet(jsonb '{"a": 1}', ARRAY['b'], jsonb '2', false);
    -- {"a": 1}
    SELECT jsonbSetLax(jsonb '{"a": 1}', ARRAY['a'], NULL);
    -- {"a": null}
    SELECT jsonbSetLax(jsonb '{"a": 1}', ARRAY['a'], NULL, true, 'delete_key');
    -- {}
    
  • Return a JSON value with a value inserted at a path

    jsonbInsert(jsonb,path text[],val jsonb,after boolean=false) → jsonb
    
    SELECT jsonbInsert(jsonb '[1, 3]', ARRAY['1'], jsonb '2');
    -- [1, 2, 3]
    SELECT jsonbInsert(jsonb '[1, 3]', ARRAY['1'], jsonb '2', true);
    -- [1, 3, 2]
    
  • Return a JSON value without its object fields whose value is null

    jsonbStripNulls(jsonb,strip_in_arrays boolean=false) → jsonb
    

    The last argument states whether null array elements are also stripped.

    SELECT jsonbStripNulls(jsonb '{"a": null, "b": [1, null]}');
    -- {"b": [1, null]}
    SELECT jsonbStripNulls(jsonb '{"a": null, "b": [1, null]}', true);
    -- {"b": [1]}
    
  • Does the JSON path return any item for a JSON value?

    jsonbPathExists(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → boolean
    jsonbPathExistsTz(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → boolean
    

    The last argument suppresses the following errors: missing object field or array element, unexpected JSON item type, datetime and numeric errors; the result of a suppressed error is NULL. The functions ending in Tz compare date and time values across time zones.

    SELECT jsonbPathExists(jsonb '{"a": [1, 2, 3]}', '$.a[*] ? (@ > 2)');
    -- true
    SELECT jsonbPathExists(jsonb '{"a": [1, 2, 3]}', '$.a[*] ? (@ > $x)', '{"x": 5}');
    -- false
    
  • Return the result of a JSON path predicate check for a JSON value

    jsonbPathMatch(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → boolean
    jsonbPathMatchTz(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → boolean
    
    SELECT jsonbPathMatch(jsonb '{"a": [1, 2, 3]}', 'exists($.a[*] ? (@ > 2))');
    -- true
    
  • Return the items a JSON path returns for a JSON value, as rows, as a JSON array, or the first one

    jsonbPathQuery(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → setof jsonb
    jsonbPathQueryTz(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → setof jsonb
    jsonbPathQueryArray(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → jsonb
    jsonbPathQueryArrayTz(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → jsonb
    jsonbPathQueryFirst(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → jsonb
    jsonbPathQueryFirstTz(jsonb,jsonpath,vars jsonb='{}',silent boolean=false) → jsonb
    
    SELECT * FROM jsonbPathQuery(jsonb '{"a": [1, 2, 3]}', '$.a[*] ? (@ >= 2)');
    -- 2
    -- 3
    SELECT jsonbPathQueryArray(jsonb '{"a": [1, 2, 3]}', '$.a[*] ? (@ >= 2)');
    -- [2, 3]
    SELECT jsonbPathQueryFirst(jsonb '{"a": [1, 2, 3]}', '$.a[*] ? (@ >= 2)');
    -- 2
    
  • Compare two JSON values, or return the hash value of a JSON value

    jsonb {=, <>, <, <=, >=, >} jsonb → boolean
    cmp(jsonb,jsonb) → integer
    hash(jsonb) → integer
    hashExtended(jsonb,seed bigint) → bigint
    

    The operators are those of PostgreSQL, and the functions eq, ne, lt, le, ge and gt answer as them, together with cmp, which returns -1, 0, or 1. Functions hash and hashExtended answer as the functions jsonb_hash and jsonb_hash_extended of PostgreSQL.

    SELECT eq(jsonb '{"a": 1}', jsonb '{"a": 1}');
    -- true
    SELECT cmp(jsonb '1', jsonb '2');
    -- -1