Функции и операторы JSON

В этом разделе описываются:

  • функции и операторы для обработки и создания данных JSON

  • язык путей SQL/JSON

Чтобы узнать больше о стандарте SQL/JSON, обратитесь к стандарту ISO/IEC TR 19075-6. Подробную информацию о типах JSON, поддерживаемых в QHB, см. в разделе Типы JSON.


Обработка и создание данных JSON

В Таблице 44 приведены имеющиеся операторы для использования с типами данных JSON (см. раздел Типы JSON). Кроме того, для типа jsonb (но не для json) имеются обычные операторы сравнения, приведенные в таблице Операторы сравнения. Эти операторы сравнения следуют правилам упорядочивания для операций B-дерева, изложенным в подразделе Индексация jsonb.

Таблица 44. Операторы для типов json и jsonb

Оператор

Описание

Пример(ы)

json -> integer → json

jsonb -> integer → jsonb

Извлекает n-й элемент массива JSON (элементы массива индексируются с нуля, но отрицательные числа считаются с конца).

'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> 2 → {"c":"baz"}

'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> -3 → {"a":"foo"}

json -> text → json

jsonb -> text → jsonb

Извлекает поле объекта JSON по заданному ключу.

'{"a": {"b":"foo"}}'::json -> 'a' → {"b":"foo"}

json ->> integer → text

jsonb ->> integer → text

Извлекает n-й элемент массива JSON в виде значения типа text.

'[1,2,3]'::json ->> 2 → 3

json ->> text → text

jsonb ->> text → text

Извлекает поле объекта JSON по заданному ключу в виде значения типа text.

'{"a":1,"b":2}'::json ->> 'b' → 2

json #> text[] → json

jsonb #> text[] → jsonb

Извлекает дочерний объект JSON по заданному пути, где элементами пути могут быть ключи полей или индексы массивов.

'{"a": {"b": ["foo","bar"]}}'::json #> '{a,b,1}' → "bar"

json #>> text[] → text

jsonb #>> text[] → text

Извлекает дочерний объект JSON по заданному пути в виде значения типа text.

'{"a": {"b": ["foo","bar"]}}'::json #>> '{a,b,1}' → bar

Примечание
Если структура входных данных JSON не соответствует запросу, например, если заданного ключа или элемента массива не существует, операторы извлечения поля/элемента/пути не выдают ошибку, а возвращают NULL.

Некоторые из следующих операторов существуют только для jsonb, как показано в Таблице 45. В подразделе Индексация jsonb описывается, как эти операторы можно использовать для эффективного поиска индексированных данных jsonb.

Таблица 45. Дополнительные операторы jsonb

Оператор

Описание

Пример(ы)

jsonb @> jsonb → boolean

В первое значение JSON вложено второе? (Подробную информацию о вложении см. в подразделе Проверка на вложение и существование в jsonb.)

'{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb → t

jsonb <@ jsonb → boolean

Первое значение JSON вложено во второе?

'{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb → t

jsonb ? text → boolean

Текстовая строка существует в значении JSON в качестве ключа верхнего уровня или элемента массива?

'{"a":1, "b":2}'::jsonb ? 'b' → t
'["a", "b", "c"]'::jsonb ? 'b' → t

jsonb ?| text[] → boolean

Какие-либо строки в текстовом массиве существуют в качестве ключей верхнего уровня или элементов массива?

'{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'd'] → t

jsonb ?& text[] → boolean

Все строки в текстовом массиве существуют в качестве ключей верхнего уровня или элементов массива?

'["a", "b", "c"]'::jsonb ?& array['a', 'b'] → t

jsonb || jsonb → jsonb

Конкатенирует два значения jsonb. Конкатенация двух массивов генерирует массив, содержащий все элементы каждого аргумента. Конкатенация двух объектов генерирует объект, содержащий объединение их ключей, при этом при наличии дубликатов ключей выбирается значение из второго объекта. Все другие случаи обрабатываются путем преобразования аргументов, отличных от массивов, в массивы с одним элементом, а затем конкатенируя их как два массива. Не работает рекурсивно: объединяются только массивы или структуры объекта на верхнем уровне.

'["a", "b"]'::jsonb || '["a", "d"]'::jsonb → ["a", "b", "a", "d"]

'{"a": "b"}'::jsonb || '{"c": "d"}'::jsonb → {"a": "b", "c": "d"}

'[1, 2]'::jsonb || '3'::jsonb → [1, 2, 3]

'{"a": "b"}'::jsonb || '42'::jsonb → [{"a": "b"}, 42]

Чтобы вставить один массив в другой за одну запись, оберните его в дополнительный слой массива, например:

'[1, 2]'::jsonb || jsonb_build_array('[3, 4]'::jsonb) → [1, 2, [3, 4]]

jsonb - text → jsonb

Удаляет ключ (и его значение) из объекта JSON или соответствующие строковые значения из массива JSON.

'{"a": "b", "c": "d"}'::jsonb - 'a' → {"c": "d"}

'["a", "b", "c", "b"]'::jsonb - 'b' → ["a", "c"]

jsonb - text[] → jsonb

Удаляет все соответствующие ключи или элементы массива из левого операнда.

'{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[] → {}

jsonb - integer → jsonb

Удаляет элемент массива с заданным индексом (отрицательные числа считаются с конца). Выдает ошибку, если значение JSON — не массив.

'["a", "b"]'::jsonb - 1 → ["a"]

jsonb #- text[] → jsonb

Удаляет поле или элемент массива по заданному пути, где элементы пути могут быть ключами полей или индексами массивов.

'["a", {"b":1}]'::jsonb #- '{1,b}' → ["a", {}]

jsonb @? jsonpath → boolean

Возвращает ли путь JSON какой-либо элемент для заданного значения JSON?

'{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)' → t

jsonb @@ jsonpath → boolean

Возвращает результат проверки предиката пути JSON для заданного значения JSON. Учитывается только первый элемент результата. Если результат не является логическим, возвращается NULL.

'{"a":[1,2,3,4,5]}'::jsonb @@ '$.a[*] > 2' → t

Примечание
Операторы jsonpath @? и @@ подавляют следующие ошибки: отсутствие поля объекта или элемента массива, неожиданный тип элемента JSON и ошибки в числах и дате/времени. Это может быть полезно при поиске в коллекциях документов JSON с различной структурой.

В Таблице 46 приведены имеющиеся функции для создания значений json и jsonb.

Таблица 46. Функции для создания JSON

Функция

Описание

Пример(ы)

to_json ( anyelement ) → json

to_jsonb ( anyelement ) → jsonb

Преобразует любое значение SQL в json или jsonb. Массивы и составные объекты преобразуются рекурсивно в массивы и объекты (многомерные массивы становятся в JSON массивами массивов). В иных случаях, если задано приведение типа данных SQL к json, то для выполнения этого преобразования используется эта функция приведения;[b] для всех остальных выдается скалярное значение JSON. Значения всех скалярных типов, кроме числового, логического и NULL, будут представлены в виде текста, в который при необходимости будет добавлено экранирование символов для получения допустимого строкового значения JSON.

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 ( anyarray [, boolean ] ) → json

Преобразует массив SQL в массив JSON. Поведение аналогично функции to_json, за исключением того, что если необязательный логический параметр равен true, между элементами массива верхнего уровня добавятся переводы строк.

array_to_json('{{1,5},{99,100}}'::int[]) → [[1,5],[99,100]]

row_to_json ( record [, boolean ] ) → json

Преобразует составное значение SQL в объект JSON. Поведение аналогично функции to_json, за исключением того, что если необязательный логический параметр равен true, между элементами верхнего уровня добавятся переводы строк.

row_to_json(row(1,'foo')) → {"f1":1,"f2":"foo"}

json_build_array ( VARIADIC "any" ) → json

jsonb_build_array ( VARIADIC "any" ) → jsonb

Формирует массив JSON (возможно, неоднородный по типам) из переменного списка аргументов. Каждый аргумент преобразуется методом to_json или to_jsonb.

json_build_array(1, 2, 'foo', 4, 5) → [1, 2, "foo", 4, 5]

json_build_object ( VARIADIC "any" ) → json

jsonb_build_object ( VARIADIC "any" ) → jsonb

Формирует объект JSON из переменного списка аргументов. По соглашению, в списке аргументов по очереди перечисляются ключи и значения. Аргументы-ключи приводятся к текстовому типу; аргументы-значения преобразуются методом to_json или to_jsonb.

json_build_object('foo', 1, 2, row(3,'bar')) → {"foo" : 1, "2" : {"f1":3,"f2":"bar"}}

json_object ( text[] ) → json

jsonb_object ( text[] ) → jsonb

Формирует объект JSON из текстового массива. Этот массив должен иметь либо ровно одну размерность с четным числом членов (в этом случае они воспринимаются как чередующиеся пары ключ/значение), либо две размерности, и при этом каждый внутренний массив содержит ровно два элемента, которые воспринимаются как пара ключ/значение. Все значения преобразуются в строки JSON.

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"}

json_object ( ключи text[], значения text[] ) → json

jsonb_object ( ключи text[], значения text[] ) → jsonb

Эта форма json_object принимает ключи и значения по парам из отдельных текстовых массивов. В остальном она идентична форме с одним аргументом.

json_object('{a,b}', '{1,2}') → {"a": "1", "b": "2"}

[b] Например, в расширении hstore определено приведение типа hstore к json, поэтому значения hstore, преобразованные посредством функций создания JSON, будут представлены в виде объектов JSON, а не примитивных строковых значений.

В Таблице 47 показаны имеющиеся функции для обработки значений json и jsonb.

Таблица 47. Функции для обработки JSON

Функция

Описание

Пример(ы)

json_array_elements ( json ) → setof json

jsonb_array_elements ( jsonb ) → setof jsonb

Разворачивает массив JSON верхнего уровня в набор значений JSON.


    select * from json_array_elements('[1,true, [2,false]]') →
       value
     -----------
     1
     true
     [2,false]

json_array_elements_text ( json ) → setof text

jsonb_array_elements_text ( jsonb ) → setof text

Разворачивает массив JSON верхнего уровня в набор значений text.


    select * from json_array_elements_text('["foo", "bar"]') →
       value
    -----------
    foo
    bar

json_array_length ( json ) → integer

jsonb_array_length ( jsonb ) → integer

Возвращает количество элементов в массиве JSON верхнего уровня.

json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]') → 5

json_each ( json ) → setof record ( ключ text, значение json )

jsonb_each ( jsonb ) → setof record ( ключ text, значение jsonb )

Разворачивает объект JSON верхнего уровня в набор пар ключ/значение.


    select * from json_each('{"a":"foo", "b":"bar"}') →
     key | value
    -----+-------
     a   | "foo"
     b   | "bar"

json_each_text ( json ) → setof record ( ключ text, значение text )

jsonb_each_text ( jsonb ) → setof record ( ключ text, значение text )

Разворачивает объект JSON верхнего уровня в набор пар ключ/значение. Возвращаемые значения будут иметь тип text.


    select * from json_each_text('{"a":"foo", "b":"bar"}') →
     key | value
    -----+-------
     a   | foo
     b   | bar

json_extract_path ( целевой_json json, VARIADIC элементы_пути text[] ) → json

jsonb_extract_path ( целевой_json jsonb, VARIADIC элементы_пути text[] ) → jsonb

Извлекает подобъект JSON по заданному пути. (Функционально это равнозначно действию оператора #>, но в некоторых случаях может быть удобнее записать путь в виде списка с переменным числом аргументов.)

json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6') → "foo"

json_extract_path_text ( целевой_json json, VARIADIC элементы_пути text[] ) → text

jsonb_extract_path_text ( целевой_json jsonb, VARIADIC элементы_пути text[] ) → text

Извлекает подобъект JSON по заданному пути в виде значения text. (Функционально это равнозначно действию оператора #>>.)

json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6') → foo

json_object_keys ( json ) → setof text

jsonb_object_keys ( jsonb ) → setof text

Возвращает набор ключей в объекте JSON верхнего уровня.


    select * from json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}') →
     json_object_keys
    ------------------
     f1
     f2

json_populate_record ( основа anyelement, целевой_json json ) → anyelement

jsonb_populate_record ( основа anyelement, целевой_json jsonb ) → anyelement

Разворачивает объект JSON верхнего уровня в строку, имеющую составной тип аргумента основа. Объект JSON сканируется на наличие полей, чьи имена соответствуют именам столбцов типа выходной строки, и их значения вставляются в эти столбцы вывода. (Поля, не соответствующие именам никаких выходных столбцов, игнорируются.) Как правило, значение основы просто равно NULL, что означает, что выходные столбцы не соответствующие полям объекта, будут заполнены значениями NULL. Однако если основа отлична от NULL, то для заполнения таких столбцов будут использованы содержащиеся в нем значения.

Для преобразования значения JSON в SQL-тип выходного столбца последовательно применяются следующие правила:

  • Значение NULL в JSON в любом случае преобразуется в значение NULL в SQL.
  • Если выходной столбец имеет тип json или jsonb, значение JSON воспроизводится без изменений.
  • Если выходной столбец имеет составной тип (тип строки) и значение JSON является объектом JSON, поля этого объекта преобразуются в столбцы типа выходной строки посредством рекурсивного применения этих правил.
  • Аналогично если выходной столбец имеет тип массива и значение JSON является массивом JSON, элементы этого массива JSON преобразуются в столбцы типа выходной строки посредством рекурсивного применения этих правил.
  • Иначе, если значение JSON является строкой, содержимое этой строки передается входной функции преобразования для типа данных целевого столбца.
  • В остальных случаях входной функции преобразования для типа данных целевого столбца передается обычное текстовое представление значения JSON.

Хотя в следующем примере используется неизменное значение JSON, обычно выполняется обращение (с помощью LATERAL) к столбцу json или jsonb из другой таблицы, находящейся в предложении FROM того же запроса. Включение функции json_populate_record в предложение FROM — удачный прием, поскольку все извлекаемые столбцы доступны для использования без необходимости в повторных вызовах функции.


    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 ( основа anyelement, целевой_json json ) → setof anyelement

jsonb_populate_recordset ( основа anyelement, целевой_json jsonb ) → setof anyelement

Разворачивает массив JSON верхнего уровня с объектами в набор строк, имеющих составной тип аргумента основа. Каждый элемент массива JSON обрабатывается так же, как описано выше для json[b]_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 ( json ) → record

jsonb_to_record ( jsonb ) → record

Разворачивает объект JSON верхнего уровня в строку, имеющую составной тип, определенный в предложении AS. (Как и со всеми функциями, возвращающими значение record, вызывающий запрос должен явно определить структуру записи в предложении AS.) Выходная запись заполняется значениями полей объекта JSON так же, как описано выше для json[b]_populate_record. Поскольку этой функции не передается значение записи, несоответствующие столбцы всегда заполняются значениями NULL.


    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 ( json ) → setof record

jsonb_to_recordset ( jsonb ) → setof record

Разворачивает массив JSON верхнего уровня с объектами в набор строк, имеющих составной тип, определенный в предложении AS. (Как и со всеми функциями, возвращающими значение record, вызывающий запрос должен явно определить структуру записи в предложении AS.) Каждый элемент массива JSON обрабатывается так же, как описано выше для json[b]_populate_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 |

jsonb_set ( цель jsonb, путь text[], новое_значение jsonb [, создать_если_отсутствует boolean ] ) → jsonb

Возвращает цель, где элемент по указанному пути заменяется новым_значением, либо новое_значение добавляется, если аргумент создать_если_отсутствует равен true (это значение по умолчанию) и элемент, на который указывает путь, не существует. Все предыдущие звенья пути должны существовать, иначе цель будет возвращена без изменений. Как и с операторами, ориентированными на пути, отрицательные целые числа, находящиеся в пути, считают элементы с конца массивов JSON. Если последнее звено пути является индексом, выходящим за границы массива, и аргумент создать_если_отсутствует равен true, новое значение добавляется в начало массива, когда индекс отрицательный, или в его конец, когда индекс положительный.

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, путь text[], новое_значение jsonb [, создать_если_отсутствует boolean [, обращение_с_null text ]] ) → jsonb

Если новое_значение отлично от NULL, эта функция ведет себя идентично jsonb_set. В противном случае она действует согласно аргументу обращение_с_null, который может принимать значения 'raise_exception' (сгенерировать исключение), 'use_json_null' (использовать NULL в JSON), 'delete_key' (удалить ключ) или 'return_target' (вернуть цель без изменений). Значение по умолчанию — 'use_json_null'.

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, путь text[], новое_значение jsonb [, вставить_после boolean ] ) → jsonb

Возвращает цель с вставленным в нее новым_значением. Если элемент, на который указывает путь, является элементом массива, новое_значение будет вставлено перед этим элементом, если параметр вставить_после равен false (это значение по умолчанию), или после него, если вставить_после равен true. Если элемент, на который указывает путь, является полем объекта, новое_значение будет вставлено, только если объект еще не содержит этот ключ. Все предыдущие звенья пути должны существовать, иначе цель будет возвращена без изменений. Как и с операторами, ориентированными на пути, отрицательные целые числа, находящиеся в пути, считают элементы с конца массивов JSON. Если последнее звено пути является индексом, выходящим за границы массива, новое значение добавляется в начало массива, когда индекс отрицательный, или в его конец, когда тот положительный.

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]}

json_strip_nulls ( json ) → json

jsonb_strip_nulls ( jsonb ) → jsonb

Рекурсивно удаляет из заданного значения JSON все поля объектов, имеющие значения NULL. Значения NULL, не относящиеся к полям объектов, не затрагиваются.

json_strip_nulls('[{"f1":1, "f2":null}, 2, null, 3]') → [{"f1":1},2,null,3]

jsonb_path_exists ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → boolean

Проверяет, возвращает ли путь JSON какой-либо элемент для заданного значения JSON. Если задается аргумент переменные, он должен быть объектом JSON, и его поля предоставляют именованные значения, подставляемые в выражение jsonpath. Если задается аргумент немой_режим и он равен true, эта функция подавляет те же ошибки, что и операторы @? и @@.

jsonb_path_exists('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') → t

jsonb_path_match ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → boolean

Возвращает результат проверки предиката пути JSON для заданного значения JSON. Учитывается только первый элемент результата. Если результат не является логическим, возвращается NULL. Необязательные аргументы переменные и немой_режим действуют так же, как и для jsonb_path_exists.

jsonb_path_match('{"a":[1,2,3,4,5]}', 'exists($.a[*] ? (@ >= $min && @ <= $max))', '{"min":2, "max":4}') → t

jsonb_path_query ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → setof jsonb

Возвращает все элементы JSON, полученные по данному пути JSON для заданного значения JSON. Необязательные аргументы переменные и немой_режим действуют так же, как и для jsonb_path_exists.


    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, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → jsonb

Возвращает все элементы JSON, полученные по данному пути JSON для заданного значения JSON, в виде массива JSON. Необязательные аргументы переменные и немой_режим действуют так же, как и для jsonb_path_exists.

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, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → jsonb

Возвращает первый элемент JSON, полученный по данному пути JSON для заданного значения JSON. Если результатов нет, возвращает NULL. Необязательные аргументы переменные и немой_режим действуют так же, как и для jsonb_path_exists.

jsonb_path_query_first('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') → 2

jsonb_path_exists_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → boolean

jsonb_path_match_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → boolean

jsonb_path_query_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → setof jsonb

jsonb_path_query_array_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → jsonb

jsonb_path_query_first_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → jsonb

Данные функции действуют подобно их двойникам без суффикса _tz, за исключением того, что эти функции поддерживают сравнение значений даты/времени, которое требует преобразований с учетом часовых поясов. В следующем примере требуется интерпретация значения даты без указания времени 2015-08-02 в виде метки времени с часовым поясом, поэтому результат зависит от текущего значения параметра TimeZone. Из-за этой зависимости данные функции помечаются как стабильные, что означает, что их нельзя использовать в индексах. Их двойники являются постоянными, и поэтому могут применяться в индексах, но при запросе на подобные сравнения они будут выдавать ошибку.

jsonb_path_exists_tz('["2015-08-01 12:00:00 -05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())') → t

jsonb_pretty ( jsonb ) → text

Преобразует заданное значение JSON в структурированный текст с отступами.

jsonb_pretty('[{"f1":1,"f2":null}, 2]') →
    [
        {
            "f1": 1,
            "f2": null
        },
        2
    ]

json_typeof ( json ) → text

jsonb_typeof ( jsonb ) → text

Возвращает тип значения JSON на верхнем уровне в виде текстовой строки. Возможные типы: object, array, string, number, boolean и null. (Не следует путать результат null со значением NULL в SQL; см. примеры.)

json_typeof('-123.4') → number

json_typeof('null'::json) → null

json_typeof(NULL::json) IS NULL → t

См. также раздел Агрегатные функции, где описывается агрегатная функция json_agg, агрегирующая значения записей в виде JSON, и агрегатная функция json_object_agg, агрегирующая пары значений в объект JSON, а также их аналоги для типа jsonb: jsonb_agg и jsonb_object_agg.



Язык путей SQL/JSON

Выражения пути SQL/JSON задают элементы, которые нужно извлечь из данных JSON аналогично выражениям XPath, используемым для доступа SQL к XML. В QHB выражения пути реализованы как тип данных jsonpath и могут использовать любые элементы, описанные в разделе Тип jsonpath.

Функции и операторы запросов JSON передают предоставленное выражение пути механизму пути для вычисления. Если выражение соответствует запрашиваемым данным JSON, возвращается соответствующий элемент или набор элементов JSON. Выражения пути написаны на языке путей SQL/JSON и могут включать в себя арифметические выражения и функции.

Выражение пути состоит из последовательности элементов, допустимых для типа данных jsonpath. Обычно выражение пути вычисляется слева направо, но при желании изменить порядок операций можно воспользоваться скобками. Если вычисление прошло успешно, создается последовательность элементов JSON и результат вычисления возвращается в функцию запроса JSON, которая завершает заданную обработку.

Для обращения к запрошенному значению JSON (элементу контекста) в выражении пути используется переменная $. За ней могут следовать один или несколько операторов аксессоров, которые опускаются в структуре JSON уровень за уровнем, чтобы извлечь подэлементы содержимого элемента контекста. Каждый последующий оператор имеет дело с результатом предыдущего этапа вычисления.

Например, предположим, у вас есть некоторые данные JSON с GPS-трекера, которые вы хотели бы проанализировать, например:

{
  "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
      }
    ]
  }
}

Для получения доступных сегментов треков вам нужно использовать оператор аксессора .ключ, чтобы спуститься сквозь окружающие объекты JSON:

$.track.segments

Для извлечения содержимого массива обычно применяется оператор [*]. Например, следующий путь вернет координаты местоположения для всех доступных сегментов треков:

$.track.segments[*].location

Чтобы вернуть координаты только первого сегмента, можно указать соответствующий нижний индекс в операторе аксессора []. Обратите внимание, что индексы массивов JSON считаются с 0:

$.track.segments[0].location

Результат каждого этапа вычисления пути может обрабатываться одним или несколькими операторами и методами jsonpath, перечисленными в подразделе Операторы и методы пути SQL/JSON. Каждому имени метода должна предшествовать точка. Например, так можно получить размер массива:

$.track.segments.size()

Дополнительные примеры использования операторов и методов jsonpath в выражениях пути см. ниже в подразделе Операторы и методы пути SQL/JSON.

При определении пути также можно использовать одно или несколько выражений фильтра, которые работают аналогично предложению WHERE в SQL. Выражение фильтра начинается со знака вопроса и содержит условие в скобках:

? (условие)

Выражения фильтра должны быть указаны сразу после того этапа вычисления пути, к которому они должны применяться. Результат этого этапа фильтруется, чтобы содержать только те элементы, которые удовлетворяют предоставленному условию. В SQL/JSON определена трехзначная логику, поэтому условие может быть true, false или unknown. Значение unknown играет ту же роль, что и NULL в SQL, и его можно проверить с помощью предиката unknown. На дальнейших этапах вычисления пути задействуются только те элементы, для которых выражение фильтра вернуло true.

Функции и операторы, которые можно использовать в выражениях фильтра, перечислены в Таблице 49. Значение, подлежащее фильтрации (т. е. результат предыдущего этапа пути), обозначается в выражении фильтра переменной @. Для получения элементов этого компонента можно написать после @ операторы аксессоров.

Например, предположим, вы хотите получить все значения частоты сердцебиений, превышающие 130. Это можно сделать с помощью следующего выражения:

$.track.segments[*].HR ? (@ > 130)

Чтобы получить время начала сегментов с такими значениями, следует перед возвратом времени начала отфильтровать ненужные сегменты, поэтому выражение фильтра применяется к предыдущему этапу, а путь, используемый в условии, отличается:

$.track.segments[*] ? (@.HR > 130)."start time"

При необходимости можно последовательно использовать несколько выражений фильтра. Например, следующее выражение выбирает время начала всех сегментов, содержащих местоположения с соответствующими координатами и высокими значениями частоты сердцебиений:

$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time"

Также допускается использование выражений фильтра на разных уровнях вложенности. В следующем примере сначала все сегменты фильтруются по местоположению, а затем для подходящих сегментов, если таковые имеются, возвращаются высокие значения частоты сердцебиений:

$.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130)

Кроме того, можно вкладывать выражения фильтра друг в друга:

$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()

Это выражение возвращает размер трека, если оно содержит сегменты с высокими значениями частоты сердцебиений, или пустую последовательность в остальных случаях.

Реализация языка путей SQL/JSON в QHB имеет следующие отклонения от стандарта SQL/JSON:

  • Выражение пути может быть логическим предикатом, хотя стандарт SQL/JSON допускает предикаты только в фильтрах. Это необходимо для реализации оператора @@. Например, в QHB допустимо следующее выражение jsonpath:

    $.track.segments[*].HR < 70
    
  • Существуют небольшие различия в интерпретации шаблонов регулярных выражений, используемых в фильтрах like_regex; эти различия описаны в подразделе Регулярные выражения SQL/JSON.


Строгий и нестрогий режимы

При запросе данных JSON выражение пути может не соответствовать фактической структуре данных JSON. Попытка получить доступ к несуществующему члену объекта или элементу массива приводит к структурной ошибке. Для выражений пути SQL/JSON существует два режима обработки структурных ошибок:

  • lax (по умолчанию) — нестрогий режим, при котором механизм пути неявно адаптирует запрошенные данные к указанному пути. Все оставшиеся структурные ошибки подавляются и преобразуются в пустые последовательности SQL/JSON.

  • strict — строгий режим, в котором при возникновении структурной ошибки она выдается как есть.

Нестрогий режим облегчает сопоставление структуры документа JSON и выражения пути, если данные JSON не соответствуют ожидаемой схеме. Если операнд не соответствует требованиям конкретной операции, перед выполнением этой операции он может автоматически оборачиваться в массив SQL/JSON или разворачиваться путем преобразования его элементов в последовательность SQL/JSON. Кроме того, операторы сравнения автоматически разворачивают свои операнды в нестрогом режиме, поэтому массивы SQL/JSON можно сравнивать, не прикладывая дополнительных усилий. Массив размером 1 считается равным своему единственному элементу. Автоматическое разворачивание не выполняется только в тех случаях, когда:

  • Выражение пути содержит методы type() или size(), которые возвращают тип и количество элементов в массиве соответственно.

  • Запрашиваемые данные JSON содержат вложенные массивы. В этом случае разворачивается только самый внешний массив, а все внутренние массивы остаются неизменными. Таким образом, на каждом этапе вычисления пути неявное развертывание может опускаться только на один уровень.

Например, при запросе перечисленных выше данных GPS в нестрогом режиме можно абстрагироваться от того факта, что в них хранится массив сегментов:

lax $.track.segments.location

В строгом режиме указанный путь должен точно соответствовать структуре запрашиваемого документа JSON, чтобы вернуть элемент SQL/JSON, поэтому использование этого выражения пути приведет к ошибке. Чтобы получить тот же результат, что и в нестрогом режиме, следует явно развернуть массив segments:

strict $.track.segments\[\*\].location

В нестрогом режиме аксессор .** может вызвать неожиданные результаты. Например, следующий запрос выберет каждое значение HR дважды:

lax $.**.HR

Это происходит из-за того, что аксессор .**выбирает и массив segments, и каждый из его элементов, тогда как аксессор .HR в нестрогом режиме автоматически разворачивает массивы. Чтобы избежать неожиданных результатов, рекомендуется использовать аксессор .** только в строгом режиме. Следующий запрос выбирает каждое значение HR только один раз:

strict $.**.HR

Операторы и методы пути SQL/JSON

В Таблице 48 показаны операторы и методы, имеющиеся в jsonpath. Обратите внимание, что унарные операторы и методы можно применять к нескольким значениям, полученным на предыдущем этапе пути, тогда как бинарные операторы (сложение и т. п.) можно применять только к отдельным значениям.

Таблица 48. Операторы и методы jsonpath

Оператор/Метод

Описание

Пример(ы)

число + числочисло

Сложение

jsonb_path_query('[2]', '$[0] + 3') → 5

+ числочисло

Унарный плюс (нет операции); в отличие от сложения, он может выполнить проход по нескольким значениям

jsonb_path_query_array('{"x": [2,3,4]}', '+ $.x') → [2, 3, 4]

число - числочисло

Вычитание

jsonb_path_query('[2]', '7 - $[0]') → 5

- числочисло

Смена знака; в отличие от вычитания, он может выполнить проход по нескольким значениям

jsonb_path_query_array('{"x": [2,3,4]}', '- $.x') → [-2, -3, -4]

число * числочисло

Умножение

jsonb_path_query('[4]', '2 * $[0]') → 8

число / числочисло

Деление

jsonb_path_query('[8.5]', '$[0] / 2') → 4.2500000000000000

число % числочисло

Остаток целочисленного деления (по модулю)

jsonb_path_query('[32]', '$[0] % 10') → 2

значение . type() → строка

Тип элемента JSON (см. json_typeof)

jsonb_path_query_array('[1, "2", {}]', '$[*].type()') → ["number", "string", "object"]

значение . size() → число

Размер элемента JSON (число элементов массива или 1, если это не массив)

jsonb_path_query('{"m": [11, 15]}', '$.m.size()') → 2

значение . double() → число

Приблизительное число с плавающей запятой, преобразованное из числа JSON или строки

jsonb_path_query('{"len": "1.9"}', '$.len.double() * 2') → 3.8

число . ceiling() → число

Ближайшее целое число, большее или равное заданному числу

jsonb_path_query('{"h": 1.3}', '$.h.ceiling()') → 2

число . floor() → число

Ближайшее целое число, меньшее или равное заданному числу

jsonb_path_query('{"h": 1.7}', '$.h.floor()') → 1

число . abs() → число

Абсолютное значение (модуль) заданного числа

jsonb_path_query('{"z": -0.3}', '$.z.abs()') → 0.3

строка . datetime() → тип_даты_времени (см. примечание)

Значение даты/времени, преобразованное из строки

jsonb_path_query('["2015-8-1", "2015-08-12"]', '$[*] ? (@.datetime() < "2015-08-2".datetime())') → "2015-8-1"

строка . datetime(шаблон) → тип_даты_времени (см. примечание)

Значение даты/времени, преобразованное из строки с помощью заданного шаблона to_timestamp

jsonb_path_query_array('["12:30", "18:40"]', '$[*].datetime("HH24:MI")') → ["12:30:00", "18:40:00"]

объект . keyvalue() → массив

Пары ключ-значение объекта, представленные в виде массива объектов, содержащего три поля: "key" (ключ), "value" (значение) и "id"; "id" представляет собой уникальный идентификатор объекта, которому принадлежит данная пара ключ-значение

jsonb_path_query_array('{"x": "20", "y": 32}', '$.keyvalue()') → [{"id": 0, "key": "x", "value": "20"}, {"id": 0, "key": "y", "value": 32}]

Примечание
Результирующим типом методов datetime() и datetime(шаблон) может быть date, timetz, time, timestamptz или timestamp. Оба метода определяют свой результирующий тип динамически.

Метод datetime() последовательно пытается сопоставить свою входную строку с форматами ISO типов date, timetz, time, timestamptz и timestamp. На первом же подходящем формате он останавливается и выдает соответствующий тип данных.

Метод datetime(шаблон) определяет результирующий тип в соответствии с полями в предоставленной строке шаблона.

Методы datetime() и datetime(шаблон) применяют те же правила синтаксического анализа, что и функция SQL to_timestamp (см. раздел Функции для форматирования типов данных), но с тремя исключениями. Во-первых, эти методы не позволяют использовать в шаблоне коды без соответствия. Во-вторых, в строке шаблона допускаются только следующие разделители: знак минуса, точка, косая черта (слэш), запятая, апостроф, точка с запятой, двоеточие и пробел. В-третьих, разделители в строке шаблона должны в точности соответствовать входной строке.

Если нужно сравнить разные типы даты/времени, применяется неявное приведение. Значение date можно привести к типу timestamp или timestamptz, timestamp — к типу timestamptz, а time — к типу timetz. Однако все эти преобразования, кроме первого, зависят от текущего значения TimeZone и поэтому могут выполняться только в функциях jsonpath, учитывающих часовой пояс.

В Таблице 49 приведены имеющиеся элементы выражения фильтра.

Таблица 49. Элементы выражения фильтра jsonpath

Предикат/Значение

Описание

Пример(ы)

значение == значение → boolean

Сравнение равенства (этот и другие операторы сравнения работают со всеми скалярными значениями JSON)

jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == 1)') → [1, 1]

jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == "a")') → ["a"]

значение != значение → boolean

значение <> значение → boolean

Сравнение неравенства

jsonb_path_query_array('[1, 2, 1, 3]', '$[*] ? (@ != 1)') → [2, 3]

jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <> "b")') → ["a", "c"]

значение < значение → boolean

Сравнение «меньше»

jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ < 2)') → [1]

значение <= значение → boolean

Сравнение «меньше или равно»

jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <= "b")') → ["a", "b"]

значение > значение → boolean

Сравнение «больше»

jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ > 2)') → [3]

значение >= значение → boolean

Сравнение «больше или равно»

jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ >= 2)') → [2, 3]

true → boolean

JSON-константа true

jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == true)') → {"name": "Chris", "parent": true}

false → boolean

JSON-константа false

jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == false)') → {"name": "John", "parent": false}

null → значение

JSON-константа null (обратите внимание, что, в отличие от SQL, сравнение с null работает нормально)

jsonb_path_query('[{"name": "Mary", "job": null}, {"name": "Michael", "job": "driver"}]', '$[*] ? (@.job == null) .name') → "Mary"

логическое_значение && логическое_значение → boolean

Логическое И

jsonb_path_query('[1, 3, 7]', '$[*] ? (@ > 1 && @ < 5)') → 3

логическое_значение || логическое_значение → boolean

Логическое ИЛИ

jsonb_path_query('[1, 3, 7]', '$[*] ? (@ < 1 || @ > 5)') → 7

! логическое_значение → boolean

Логическое НЕ

jsonb_path_query('[1, 3, 7]', '$[*] ? (!(@ < 5))') → 7

логическое_значение is unknown → boolean

Проверяет, является ли unknown логическим условием.

jsonb_path_query('[-1, 2, 7, "foo"]', '$[*] ? ((@ > 0) is unknown)') → "foo"

строка like_regex строка [ flag строка ] → boolean

Проверяет, соответствует ли первый операнд регулярному выражению, заданному во втором операнде, с необязательными модификациями, описываемыми строкой символов flag (см. подраздел Регулярные выражения SQL/JSON).

jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c")') → ["abc", "abdacb"]

jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c" flag "i")') → ["abc", "aBdC", "abdacb"]

строка starts with строка → boolean

Проверяет, является ли второй операнд начальной подстрокой первого.

jsonb_path_query('["John Smith", "Mary Stone", "Bob Johnson"]', '$[*] ? (@ starts with "John")') → "John Smith"

exists ( выражение_пути ) → boolean

Проверяет, соответствует ли выражение пути хотя бы одному элементу SQL/JSON. Возвращает unknown, если это выражение пути могло вызвать ошибку; это используется во втором примере, чтобы избежать ошибки «ключ не найден» в строгом режиме.

jsonb_path_query('{"x": [1, 2], "y": [2, 4]}', 'strict $.* ? (exists (@ ? (@[*] > 2)))') → [2, 4]

jsonb_path_query_array('{"value": 41}', 'strict $ ? (exists (@.name)) .name') → []


Регулярные выражения SQL/JSON

Выражения путей SQL/JSON позволяют сопоставлять текст с регулярным выражением при помощи фильтра like_regex. Например, следующий запрос пути SQL/JSON будет соответствовать всем строкам в массиве, которые начинаются с английской гласной, без учета регистра:

$[*] ? (@ like_regex "^[aeiou]" flag "i")

Необязательная строка flag может включать один или несколько следующих символов: i — сопоставления без учета регистра, m — допускается сопоставление ^ и $ с переводами строк, s — допускается сопоставление . с переводом строки, и q — заключить в кавычки весь шаблон (сводя поиск к простому сопоставлению подстроки).

Стандарт SQL/JSON заимствует свое определение для регулярных выражений из оператора LIKE_REGEX, в котором, в свою очередь, используется стандарт XQuery. В настоящее время в QHB оператор LIKE_REGEX не поддерживается. Поэтому фильтр like_regex реализован с использованием механизма регулярных выражений POSIX, описанного в подразделе Регулярные выражения POSIX. Это приводит к различным незначительным несоответствиям стандартному поведению SQL/JSON, которые каталогизированы в подразделе Отличия от XQuery (LIKE_REGEX). Тем не менее, обратите внимание, что описанные там несовместимости флаговых букв не применяются к SQL/JSON, поскольку в SQL/JSON флаговые буквы XQuery переводятся во флаги, подходящие механизму POSIX.

Не забывайте, что аргумент шаблона like_regex является строковым литералом пути JSON, написанным в соответствии с правилами, приведенными в подразделе Тип jsonpath. В частности, это означает, что все обратные слеши в регулярном выражении необходимо дублировать. Например, чтобы сопоставить строковые значения корневого документа, содержащие только цифры, нужно написать следующее:

$.* ? (@ like_regex "^\\d+$")