9.15. Функции и операторы JSON
В этом разделе описываются:
функции и операторы, предназначенные для работы с данными JSON
язык путей SQL/JSON
Чтобы узнать больше о стандарте SQL/JSON, обратитесь к [sqltr-19075-6]. Типы JSON, поддерживаемые в PostgreSQL, описаны в Разделе 8.14.
9.15.1. Обработка и создание данных JSON
В Таблице 9.44 перечислены операторы, которые можно использовать с типами данных JSON (см. Раздел 8.14).
Таблица 9.44. Операторы для типов json
и jsonb
Оператор | Тип правого операнда | Тип результата | Описание | Пример | Результат примера |
---|---|---|---|---|---|
-> | int | json или jsonb | Выдаёт элемент массива JSON (по номеру от 0, отрицательные числа задают позиции с конца) | '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json->2 | {"c":"baz"} |
-> | text | json или jsonb | Выдаёт поле объекта JSON по ключу | '{"a": {"b":"foo"}}'::json->'a' | {"b":"foo"} |
->> | int | text | Выдаёт элемент массива JSON в типе text | '[1,2,3]'::json->>2 | 3 |
->> | text | text | Выдаёт поле объекта JSON в типе text | '{"a":1,"b":2}'::json->>'b' | 2 |
#> | text[] | json или jsonb | Выдаёт объект JSON по заданному пути | '{"a": {"b":{"c": "foo"}}}'::json#>'{a,b}' | {"c": "foo"} |
#>> | text[] | text | Выдаёт объект JSON по заданному пути в типе text | '{"a":[1,2,3],"b":[4,5,6]}'::json#>>'{a,2}' | 3 |
Примечание
Эти операторы существуют в двух вариациях для типов json
и jsonb
. Операторы извлечения поля/элемента/пути возвращают тот же тип, что у операнда слева (json
или jsonb
), за исключением тех, что возвращают тип text
(они возвращают значение как текстовое). Если входные данные JSON не содержат структуры, удовлетворяющей запросу, например в них нет искомого элемента, то операторы извлечения поля/элемента/пути не выдают ошибку, а возвращают NULL. Все операторы извлечения поля/элемента/пути, принимающие целочисленные позиции в массивах JSON, поддерживают и отсчёт от конца массива по отрицательной позиции.
Стандартные операторы сравнения, приведённые в Таблице 9.1, есть для типа jsonb
, но не для json
. Они следуют правилам сортировки для операций B-дерева, описанным в Подразделе 8.14.4. В Разделе 9.20 вы также можете узнать об агрегатной функции json_agg
, которая агрегирует значения записи в виде JSON, и агрегатной функции json_object_agg
, агрегирующей пары значений в объект JSON, а также их аналогах для jsonb
, функциях jsonb_agg
и jsonb_object_agg
.
Некоторые из следующих операторов существуют только для jsonb
, как показано в Таблице 9.45. Многие из этих операторов могут быть проиндексированы с помощью классов операторов jsonb
. Полное описание проверок на вхождение и существование для jsonb
приведено в Подразделе 8.14.3. Как эти операторы могут использоваться для эффективного индексирования данных jsonb
, описано в Подразделе 8.14.4.
Таблица 9.45. Дополнительные операторы jsonb
Оператор | Тип правого операнда | Описание | Пример |
---|---|---|---|
@> | jsonb | Левое значение JSON содержит на верхнем уровне путь/значение JSON справа? | '{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb |
<@ | jsonb | Путь/значение JSON слева содержится на верхнем уровне в правом значении JSON? | '{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb |
? | text | Присутствует ли строка в качестве ключа верхнего уровня в значении JSON? | '{"a":1, "b":2}'::jsonb ? 'b' |
?| | text[] | Какие-либо строки массива присутствуют в качестве ключей верхнего уровня? | '{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'c'] |
?& | text[] | Все строки массива присутствуют в качестве ключей верхнего уровня? | '["a", "b"]'::jsonb ?& array['a', 'b'] |
|| | jsonb | Соединяет два значения jsonb в новое значение jsonb | '["a", "b"]'::jsonb || '["c", "d"]'::jsonb |
- | text | Удаляет пару ключ/значение или элемент-строку из левого операнда. Пары ключ/значение выбираются по значению ключа. | '{"a": "b"}'::jsonb - 'a' |
- | text[] | Удаляет множество пар ключ/значение или элементы-строки из левого операнда. Пары ключ/значение выбираются по значению ключа. | '{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[] |
- | integer | Удаляет из массива элемент в заданной позиции (отрицательные номера позиций отсчитываются от конца). Выдаёт ошибку, если контейнер верхнего уровня — не массив. | '["a", "b"]'::jsonb - 1 |
#- | text[] | Удаляет поле или элемент с заданным путём (для массивов JSON отрицательные номера позиций отсчитываются от конца) | '["a", {"b":1}]'::jsonb #- '{1,b}' |
@? | jsonpath | Выдаёт ли путь JSON какой-либо элемент для заданного значения JSON? | '{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)' |
@@ | jsonpath | Возвращает результат проверки предиката пути JSON для заданного значения JSON. При этом учитывается только первый элемент результата. Если результат не является логическим, возвращается null . | '{"a":[1,2,3,4,5]}'::jsonb @@ '$.a[*] > 2' |
Примечание
Оператор ||
соединяет два объекта JSON вместе, формируя объект с объединённым набором ключей и значений, при этом в случае совпадения ключей выбирается значение из второго объекта. С любыми другими аргументами формируется массив JSON: сначала любой аргумент, отличный от массива, преобразуется в одноэлементный массив, а затем два полученных массива соединяются. Эта операция не рекурсивна — объединение производится только на верхнем уровне структуры объекта или массива.
Примечание
Операторы @?
и @@
подавляют следующие ошибки: отсутствие поля объекта или элемента массива, несовпадение типа элемента JSON и числовые ошибки. Это может быть полезно, когда нужно произвести поиск по набору документов JSON, имеющих различную структуру.
В Таблице 9.46 показаны функции, позволяющие создавать значения типов json
и jsonb
. (Для типа jsonb
нет аналогов функций row_to_json
и array_to_json
, но практически тот же результат можно получить с помощью to_jsonb
.)
Таблица 9.46. Функции для создания JSON
Функция | Описание | Пример | Результат примера |
---|---|---|---|
| Возвращает значение в виде json или jsonb . Массивы и составные структуры преобразуются (рекурсивно) в массивы и объекты; для других типов, для которых определено приведение к json , применяется эта функция приведения, а для всех остальных выдаётся скалярное значение. Значения всех скалярных типов, кроме числового, логического и NULL, представляются в текстовом виде, в стиле, допустимом для значений json или jsonb . | to_json('Fred said "Hi."'::text) | "Fred said \"Hi.\"" |
array_to_json(anyarray [, pretty_bool]) | Возвращает массив в виде массива JSON. Многомерный массив PostgreSQL становится массивом массивов JSON. Если параметр pretty_bool равен true, между элементами 1-ой размерности вставляются разрывы строк. | array_to_json('{{1,5},{99,100}}'::int[]) | [[1,5],[99,100]] |
row_to_json(record [, pretty_bool]) | Возвращает кортеж в виде объекта JSON. Если параметр pretty_bool равен true, между элементами 1-ой размерности вставляются разрывы строк. | row_to_json(row(1,'foo')) | {"f1":1,"f2":"foo"} |
| Формирует массив JSON (возможно, разнородный) из переменного списка аргументов. | json_build_array(1,2,'3',4,5) | [1, 2, "3", 4, 5] |
| Формирует объект JSON из переменного списка аргументов. По соглашению в этом списке перечисляются по очереди ключи и значения. | json_build_object('foo',1,'bar',2) | {"foo": 1, "bar": 2} |
| Формирует объект JSON из текстового массива. Этот массив должен иметь либо одну размерность с чётным числом элементов (в этом случае они воспринимаются как чередующиеся ключи/значения), либо две размерности и при этом каждый внутренний массив содержит ровно два элемента, которые воспринимаются как пара ключ/значение. |
| {"a": "1", "b": "def", "c": "3.5"} |
| Эта форма json_object принимает ключи и значения по парам из двух отдельных массивов. Во всех остальных отношениях она не отличается от формы с одним аргументом. | json_object('{a, b}', '{1,2}') | {"a": "1", "b": "2"} |
Примечание
Функции array_to_json
и row_to_json
подобны to_json
, но предлагают возможность улучшенного вывода. Действие to_json
, описанное выше, распространяется на каждое отдельное значение, преобразуемое этими функциями.
Примечание
В расширении hstore определено преобразование из hstore
в json
, так что значения hstore
, преобразуемые функциями создания JSON, будут представлены в виде объектов JSON, а не как примитивные строковые значения.
В Таблице 9.47 показаны функции, предназначенные для работы со значениями json
и jsonb
.
Таблица 9.47. Функции для обработки JSON
Функция | Тип результата | Описание | Пример | Результат примера |
---|---|---|---|---|
| int | Возвращает число элементов во внешнем массиве JSON. | json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]') | 5 |
|
| Разворачивает внешний объект JSON в набор пар ключ/значение (key/value). | select * from json_each('{"a":"foo", "b":"bar"}') | key | value -----+------- a | "foo" b | "bar" |
| setof key text, value text | Разворачивает внешний объект JSON в набор пар ключ/значение (key/value). Возвращаемые значения будут иметь тип text . | select * from json_each_text('{"a":"foo", "b":"bar"}') | key | value -----+------- a | foo b | bar |
|
| Возвращает значение JSON по пути, заданному элементами пути (path_elems ) (равнозначно оператору #> operator). | json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}','f4') | {"f5":99,"f6":"foo"} |
| text | Возвращает значение JSON по пути, заданному элементами пути path_elems , как text (равнозначно оператору #>> ). | json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}','f4', 'f6') | foo |
| setof text | Возвращает набор ключей во внешнем объекте JSON. | json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}') | json_object_keys ----------------- f1 f2 |
| anyelement | Разворачивает объект из from_json в табличную строку, в которой столбцы соответствуют типу строки, заданному параметром base (см. примечания ниже). | select * from json_populate_record(null::myrowtype, '{"a": 1, "b": ["2", "a b"], "c": {"d": 4, "e": "a b c"}}') | a | b | c ---+-----------+------------- 1 | {2,"a b"} | (4,"a b c") |
| setof anyelement | Разворачивает внешний массив объектов из from_json в набор табличных строк, в котором столбцы соответствуют типу строки, заданному параметром base (см. примечания ниже). | select * from json_populate_recordset(null::myrowtype, '[{"a":1,"b":2},{"a":3,"b":4}]') | a | b ---+--- 1 | 2 3 | 4 |
|
| Разворачивает массив JSON в набор значений JSON. | select * from json_array_elements('[1,true, [2,false]]') | value ----------- 1 true [2,false] |
| setof text | Разворачивает массив JSON в набор значений text . | select * from json_array_elements_text('["foo", "bar"]') | value ----------- foo bar |
| text | Возвращает тип внешнего значения JSON в виде текстовой строки. Возможные типы: object , array , string , number , boolean и null . | json_typeof('-123.4') | number |
| record | Формирует обычную запись из объекта JSON (см. примечания ниже). Как и со всеми функциями, возвращающими record , при вызове необходимо явно определить структуру записи с помощью предложения AS . | 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") |
| setof record | Формирует обычный набор записей из массива объекта JSON (см. примечания ниже). Как и со всеми функциями, возвращающими record , при вызове необходимо явно определить структуру записи с помощью предложения AS . | select * from json_to_recordset('[{"a":1,"b":"foo"},{"a":"2","c":"bar"}]') as x(a int, b text); | a | b ---+----- 1 | foo 2 | |
|
| Возвращает значение from_json , из которого исключаются все поля объекта, содержащие значения NULL. Другие значения NULL остаются нетронутыми. | json_strip_nulls('[{"f1":1,"f2":null},2,null,3]') | [{"f1":1},2,null,3] |
|
| Возвращает значение target , в котором раздел с заданным путём (path ) заменяется новым значением (new_value ), либо в него добавляется значение new_value , если аргумент create_missing равен true (это значение по умолчанию) и элемент, на который ссылается path , не существует. Как и с операторами, рассчитанными на пути, отрицательные числа в пути (path ) обозначают отсчёт от конца массивов JSON. |
|
|
|
| Возвращает значение target с вставленным в него новым значением new_value . Если место в target , выбранное путём path , оказывается в массиве JSONB, new_value будет вставлен до (по умолчанию) или после (если параметр insert_after равен true) выбранной позиции. Если место в target , выбранное путём path , оказывается в объекте JSONB, значение new_value будет вставлено в него, только если заданный путь path не существует. Как и с операторами, рассчитанными на пути, отрицательные числа в пути (path ) обозначают отсчёт от конца массивов JSON. |
|
|
|
| Возвращает значение from_json в виде текста JSON с отступами. | jsonb_pretty('[{"f1":1,"f2":null},2,null,3]') | [ { "f1": 1, "f2": null }, 2, null, 3 ] |
| boolean | Определяет, выдаёт ли путь JSON какой-либо элемент при заданном значении JSON. |
|
|
| boolean | Возвращает результат проверки предиката пути JSON для заданного значения JSON. При этом учитывается только первый элемент результата. Если результат не является логическим, возвращается null . |
|
|
| setof jsonb | Возвращает все элементы JSON, которые выдаёт путь JSON для заданного значения JSON. |
| jsonb_path_query ------------------ 2 3 4 |
| jsonb | Возвращает все элементы JSON, которые выдаёт путь JSON для заданного значения JSON, оборачивая их в массив. |
|
|
| jsonb | Возвращает первый элемент JSON, который выдаётся выражением пути для заданного значения JSON. В случае отсутствия результатов возвращает NULL . |
|
|
Примечание
Многие из этих функций и операторов преобразуют спецпоследовательности Unicode в JSON-строках в соответствующие одиночные символы. Для входных данных типа jsonb
это ничем не грозит, так как преобразование уже выполнено; однако для типа json
в результате может произойти ошибка, как отмечено в Разделе 8.14.
Примечание
Функции json[b]_populate_record
, json[b]_populate_recordset
, json[b]_to_record
и json[b]_to_recordset
принимают объект JSON или массив объектов и извлекают значения, связанные с ключами, по именам, соответствующим именам столбцов выходного типа. Поля объектов, не соответствующие никаким именам выходных столбцов, игнорируются, а выходные столбцы, для которых не находятся поля в объекте, заполняются значениями NULL. Для преобразования значения JSON в тип SQL выходного столбца последовательно применяются следующие правила:
Значение NULL в JSON всегда преобразуется в SQL NULL.
Если выходной столбец имеет тип
json
илиjsonb
, значение JSON воспроизводится без изменений.Если выходной столбец имеет составной тип (тип кортежа) и значение JSON является объектом JSON, поля этого объекта преобразуются в столбцы типа выходного кортежа в результате рекурсивного применения этих правил.
Подобным образом, если выходной столбец имеет тип-массив и значение JSON представляет массив JSON, элементы данного массива преобразуются в элементы выходного массива в результате рекурсивного применения этих правил.
Если же значение JSON является строковой константой, содержимое этой строки передаётся входной функции преобразования для типа данных целевого столбца.
В противном случае функции преобразования для типа данных целевого столбца передаётся обычное текстовое представление значения JSON.
Хотя в примерах использования перечисленных функций применяются константы, обычно эти функции обращаются к таблицам в предложении FROM
, а в качестве аргумента указывается один из столбцов типа json
или jsonb
. Извлечённые значения затем могут использоваться в других частях запроса, например, в предложениях WHERE
и результирующих списках. Извлекая множество значений подобным образом, можно значительно увеличить производительность по сравнению с использованием операторов, работающих с отдельными ключами.
Примечание
В target
должны присутствовать все элементы пути, заданного параметром path
функций jsonb_set
и jsonb_insert
, за исключением последнего. Если create_missing
равен false, должны присутствовать абсолютно все элементы пути path
, переданного функции jsonb_set
. Если это условие не выполняется, значение target
возвращается неизменённым.
Если последним элементом пути оказывается ключ объекта, он будет создан в случае отсутствия и получит новое значение. Если последний элемент пути — позиция в массиве, то когда она положительна, целевой элемент отсчитывается слева, а когда отрицательна — справа, то есть -1
указывает на самый правый элемент и т. д. Если позиция лежит вне диапазона -длина_массива .. длина_массива -1, и параметр create_missing равен true, новое значение добавляется в начало массива, если позиция отрицательна, и в конец, если положительна.
Примечание
Значение null
, возвращаемое функцией json_typeof
, не следует путать с SQL NULL. Тогда как при вызове json_typeof('null'::json)
возвращается null
, при вызове json_typeof(NULL::json)
будет возвращено значение SQL NULL.
Примечание
Если аргумент функции json_strip_nulls
содержит повторяющиеся имена полей в любом объекте, в результате могут проявиться семантические различия, в зависимости от порядка этих полей. Это не проблема для функции jsonb_strip_nulls
, так как в значениях jsonb
имена полей не могут дублироваться.
Примечание
Функции jsonb_path_exists
, jsonb_path_match
, jsonb_path_query
, jsonb_path_query_array
и jsonb_path_query_first
принимают дополнительно необязательные аргументы vars
и silent
.
В аргументе vars
можно передать объект, содержащий именованные переменные, которые будут подставляться в выражение jsonpath
.
Если передаётся аргумент silent
и он имеет значение true
, эти функции подавляют те же ошибки, что и операторы @?
и @@
.
9.15.2. Язык путей SQL/JSON
Выражения путей SQL/JSON определяют элементы, извлекаемые из данных JSON, подобно тому, как выражения XPath позволяют обращаться из SQL к XML. В PostgreSQL выражения путей представляются в виде типа данных jsonpath
и могут использовать любые элементы, описанные в Подразделе 8.14.6.
Операторы и функции запросов к JSON передают поступившее им выражение обработчику путей для вычисления. Если выражению соответствуют фигурирующие в запросе данные JSON, в результате выдаётся соответствующий элемент SQL/JSON. Выражения путей записываются на языке SQL/JSON и могут включать сложные арифметические выражения и функции. Функции запросов принимают такие выражения в виде текстовых строк, поэтому их нужно заключать в апострофы.
Выражение пути состоит из последовательности элементов, допустимых для типа jsonpath
. Вычисляется оно слева направо, но при необходимости порядок операций можно изменить, добавив скобки. В случае успешного вычисления выдаётся последовательность элементов SQL/JSON (последовательность SQL/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'
Чтобы получить координаты только первого сегмента, можно задать соответствующий индекс в операторе обращения []
. Заметьте, что индексы массивов в SQL/JSON отсчитываются с 0:
'$.track.segments[0].location'
Результат каждого шага вычисления выражения может быть обработан операторами и методами jsonpath
, перечисленными в Подразделе 9.15.2.3. Перед именем метода должна стоять точка. Например, так можно получить размер массива:
'$.track.segments.size()'
Дополнительные примеры использования операторов и методов jsonpath
в выражениях пути приведены в Подразделе 9.15.2.3.
Определяя путь, также можно использовать выражения фильтра, работающие подобно предложению WHERE
в SQL. Выражение фильтра начинается со знака вопроса и содержит условие в скобках:
? (условие
)
Выражение фильтра должно указываться сразу после шага вычисления пути, к которому оно применяется. Результаты этого шага проходят через фильтр, и на выходе остаются только те элементы, которые удовлетворяют заданному условию. В SQL/JSON действует троичная логика, то есть результатом выражения может быть true
, false
или unknown
(неизвестность). Значение unknown
играет ту же роль, что и NULL
в SQL, и может быть проверено предикатом is unknown
. На последующих шагах вычисления пути будут обрабатываться только те элементы, для которых выражение фильтра выдало true
.
Функции и операторы, которые можно использовать в выражениях фильтра, перечислены в Таблице 9.49. Результат вычисления пути, проходящий через фильтр, представляется переменной @
. Чтобы обратиться к элементу JSON, находящемуся на более низком уровне вложенности, добавьте после @
один или несколько операторов обращения.
Предположим, что вы хотите получить все показатели пульса, превышающие 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 в PostgreSQL имеет следующие отличия от стандарта SQL/JSON:
Метод
.datetime()
ещё не реализован, потому что постоянные функции и операторыjsonpath
не могут использовать часовой пояс текущего сеанса, а это необходимо в некоторых операциях с датой/временем. Поддержка дат/времени будет добавлена вjsonpath
в будущих версиях PostgreSQL.Выражение пути может быть булевым предикатом, хотя стандарт SQL/JSON допускает предикаты только в фильтрах. Это необходимо для реализации оператора
@@
. Например, следующее выражениеjsonpath
допускается в PostgreSQL:'$.track.segments[*].HR < 70'
Есть небольшие различия в интерпретации шаблонов регулярных выражений, используемых в фильтрах
like_regex
; имеющиеся особенности описаны в Подразделе 9.15.2.2.
9.15.2.1. Строгий и нестрогий режимы
Когда вы обращаетесь к данным JSON, выражение пути может не соответствовать фактической структуре данных JSON. Попытка обратиться к несуществующему члену объекта или элементу массива приводит к ошибке структурного типа. Для обработки такого рода ошибок в выражениях путей SQL/JSON предусмотрены два режима:
lax (по умолчанию) — нестрогий режим, в котором обработчик путей неявно адаптирует обрабатываемые данные к указанному пути. Любые возникающие структурные ошибки подавляются и заменяются пустыми последовательностями SQL/JSON.
strict — строгий режим, в котором структурные ошибки выдаются как есть.
Нестрогий режим упрощает сопоставление структуры документа JSON с выражением пути в случаях, когда данные JSON не соответствуют ожидаемой схеме. Если операнд не удовлетворяет требованиям определённой операции, он может перед выполнением этой операции автоматически оборачиваться в массив SQL/JSON или наоборот, разворачиваться так, чтобы его элементы образовали последовательность SQL/JSON. Помимо этого, в нестрогом режиме операторы сравнения автоматически разворачивают свои операнды, что позволяет легко сравнивать массивы SQL/JSON. Массив с одним элементом в таком режиме считается равным своему элементу. Автоматическое разворачивание не выполняется только в следующих случаях:
В выражении пути фигурируют методы
size()
иtype()
, возвращающие соответственно число элементов в массиве и тип.Обрабатываемые данные JSON содержат вложенные массивы. В этом случае разворачивается только массив верхнего уровня, а внутренние массивы остаются без изменений. Таким образом, неявное разворачивание может опускаться на каждом шаге вычисления пути только на один уровень.
Например, обрабатывая данные GPS, показанные выше, в нестрогом режиме можно не обращать внимание на то, что в них содержится массив сегментов:
'lax $.track.segments.location'
В строгом режиме указанный путь должен в точности соответствовать структуре обрабатываемого документа JSON и выдавать элемент SQL/JSON, поэтому использование такого выражения пути приведёт к ошибке. Чтобы получить такой же результат, как в нестрогом режиме, необходимо явно развернуть массив segments
:
'strict $.track.segments[*].location'
Оператор обращения .**
в нестрогом режиме может выдавать несколько неожиданные результаты. Например, следующий запрос выберет каждое значение HR
дважды:
lax $.**.HR
Это происходит потому, что оператор .**
выбирает и массив segments
, и каждый из его элементов, а обращение .HR
в нестрогом режиме автоматически разворачивает массивы. Во избежание подобных сюрпризов мы рекомендуем использовать оператор обращения .**
только в строгом режиме. Следующий запрос выбирает каждое значение HR
в единственном экземпляре:
strict $.**.HR
9.15.2.2. Регулярные выражения
Выражения путей SQL/JSON могут содержать фильтры like_regex
, позволяющие сопоставлять текст с регулярным выражением. Например, следующий запрос пути SQL/JSON выберет все строки в массиве, которые начинаются с английской гласной в любом регистре:
'$[*] ? (@ like_regex "^[aeiou]" flag "i")'
Необязательная строка flag
может содержать один или несколько следующих символов: i
, делающий поиск регистронезависимым, m
, допускающий сопоставление ^
и $
с переводами строк, s
, допускающий сопоставление .
с символом новой строки, и q
, берущий в кавычки весь шаблон (в результате производится простой поиск подстроки).
Стандарт SQL/JSON заимствует определение регулярных выражений от оператора LIKE_REGEX
, который, в свою очередь, реализуется по стандарту XQuery. Однако в PostgreSQL оператор LIKE_REGEX
в настоящее время отсутствует. Поэтому фильтр like_regex
реализован с использованием механизма регулярных выражений POSIX, который описан в Подразделе 9.7.3. Вследствие этого наблюдается ряд небольших отклонений от описанного в стандарте поведения SQL/JSON, о которых рассказывается в Подразделе 9.7.3.8. Заметьте однако, что описанная там несовместимость букв флагов не проявляется на уровне SQL/JSON, так как заданные в SQL/JSON флаги XQuery переводятся во флаги, воспринимаемые механизмом POSIX.
Помните, что аргумент, задающий шаблон для like_regex
, является строкой пути JSON и записывается по правилам, описанным в Подразделе 8.14.6. Это в частности означает, что каждую косую черту в регулярном выражении надо дублировать. Например, чтобы отобрать строковые значения, находящиеся на уровне корня документа и содержащие только цифры, нужно написать:
$.* ? (@ like_regex "^\\d+$")
9.15.2.3. Операторы и методы SQL/JSON
В Таблице 9.48 перечислены операторы и методы, которые можно использовать в jsonpath
. В Таблице 9.49 показаны возможные элементы выражения фильтра.
Таблица 9.48. Операторы и методы jsonpath
Оператор/Метод | Описание | Пример JSON | Пример запроса | Результат |
---|---|---|---|---|
+ (унарный) | Оператор «плюс», применяемый к элементам последовательности SQL/JSON | {"x": [2.85, -14.7, -9.4]} | + $.x.floor() | 2, -15, -10 |
- (унарный) | Оператор «минус», применяемый к элементам последовательности SQL/JSON | {"x": [2.85, -14.7, -9.4]} | - $.x.floor() | -2, 15, 10 |
+ (бинарный) | Сложение | [2] | 2 + $[0] | 4 |
- (бинарный) | Вычитание | [2] | 4 - $[0] | 2 |
* | Умножение | [4] | 2 * $[0] | 8 |
/ | Деление | [8] | $[0] / 2 | 4 |
% | Остаток от деления | [32] | $[0] % 10 | 2 |
type() | Тип элемента SQL/JSON | [1, "2", {}] | $[*].type() | "number", "string", "object" |
size() | Размер элемента SQL/JSON | {"m": [11, 15]} | $.m.size() | 2 |
double() | Приблизительное число с плавающей точкой, преобразованное из строки или числа SQL/JSON | {"len": "1.9"} | $.len.double() * 2 | 3.8 |
ceiling() | Ближайшее целое, большее или равное числу SQL/JSON | {"h": 1.3} | $.h.ceiling() | 2 |
floor() | Ближайшее целое, меньшее или равное числу SQL/JSON | {"h": 1.3} | $.h.floor() | 1 |
abs() | Модуль числа SQL/JSON (абсолютное значение) | {"z": -0.3} | $.z.abs() | 0.3 |
keyvalue() | Последовательность пар ключ-значение, представленная в виде массива элементов, содержащих три поля ("key" , "value" и "id" ). В поле id содержится уникальный идентификатор объекта, к которому относится данная пара ключ-значение. | {"x": "20", "y": 32} | $.keyvalue() | {"key": "x", "value": "20", "id": 0}, {"key": "y", "value": 32, "id": 0} |
Таблица 9.49. Элементы выражения фильтра jsonpath
Значение/Предикат | Описание | Пример JSON | Пример запроса | Результат |
---|---|---|---|---|
== | Оператор равенства | [1, 2, 1, 3] | $[*] ? (@ == 1) | 1, 1 |
!= | Оператор неравенства | [1, 2, 1, 3] | $[*] ? (@ != 1) | 2, 3 |
<> | Оператор неравенства (синоним != ) | [1, 2, 1, 3] | $[*] ? (@ <> 1) | 2, 3 |
< | Оператор «меньше» | [1, 2, 3] | $[*] ? (@ < 2) | 1 |
<= | Оператор «меньше или равно» | [1, 2, 3] | $[*] ? (@ <= 2) | 1, 2 |
> | Оператор «больше» | [1, 2, 3] | $[*] ? (@ > 2) | 3 |
>= | Оператор «больше или равно» | [1, 2, 3] | $[*] ? (@ >= 2) | 2, 3 |
true | Значение, которое можно сравнить с логическим значением JSON true | [{"name": "John", "parent": false}, {"name": "Chris", "parent": true}] | $[*] ? (@.parent == true) | {"name": "Chris", "parent": true} |
false | Значение, которое можно сравнить с логическим значением JSON false | [{"name": "John", "parent": false}, {"name": "Chris", "parent": true}] | $[*] ? (@.parent == false) | {"name": "John", "parent": false} |
null | Значение, которое можно сравнить со значением JSON null | [{"name": "Mary", "job": null}, {"name": "Michael", "job": "driver"}] | $[*] ? (@.job == null) .name | "Mary" |
&& | Логическое И | [1, 3, 7] | $[*] ? (@ > 1 && @ < 5) | 3 |
|| | Логическое ИЛИ | [1, 3, 7] | $[*] ? (@ < 1 || @ > 5) | 7 |
! | Логическое НЕ | [1, 3, 7] | $[*] ? (!(@ < 5)) | 7 |
like_regex | Проверяет, соответствует ли первый операнд регулярному выражению, которое задаёт второй операнд с необязательным аргументом flag , влияющим на поведение выражения (см. Подраздел 9.15.2.2) | ["abc", "abd", "aBdC", "abdacb", "babc"] | $[*] ? (@ like_regex "^ab.*c" flag "i") | "abc", "aBdC", "abdacb" |
starts with | Проверяет, является ли второй операнд начальной подстрокой первого | ["John Smith", "Mary Stone", "Bob Johnson"] | $[*] ? (@ starts with "John") | "John Smith" |
exists | Проверяет, соответствует ли выражению пути минимум один элемент SQL/JSON | {"x": [1, 2], "y": [2, 4]} | strict $.* ? (exists (@ ? (@[*] > 2))) | 2, 4 |
is unknown | Проверяет, является ли unknown результатом логического условия | [-1, 2, 7, "infinity"] | $[*] ? ((@ > 0) is unknown) | "infinity" |