9.16. Функции и операторы JSON#
9.16. Функции и операторы JSON
Этот раздел описывает:
функции и операторы для обработки и создания данных JSON
язык SQL/JSON пути
Чтобы узнать больше о стандарте SQL/JSON, см. [sqltr-19075-6]. Для получения подробной информации о типах JSON, поддерживаемых в Tantor SE, см. Раздел 8.14.
9.16.1. Обработка и создание данных JSON
Таблица 9.45 показывает операторы, которые доступны для использования с типами данных JSON (см. Раздел 8.14).
Кроме того, обычные операторы сравнения, показанные в Таблица 9.1, доступны для типа jsonb
, но не для типа json
. Операторы сравнения следуют правилам упорядочивания для операций B-дерева, описанным в Раздел 8.14.4.
См. также Раздел 9.21 для получения информации об агрегатной функции json_agg
, которая агрегирует значения записей в JSON, агрегатной функций json_object_agg
, которая агрегирует пары значений в JSON-объект, и их эквиваленты для типа jsonb
, jsonb_agg
и jsonb_object_agg
.
Таблица 9.45. json
и jsonb
Операторы
Оператор Описание Пример(ы) |
---|
Извлекает
|
Извлекает поле объекта JSON с заданным ключом.
|
Извлекает
|
Извлекает поле объекта JSON с заданным ключом, как
|
Извлекает подобъект JSON по указанному пути, где элементы пути могут быть ключами полей или индексами массива.
|
Извлекает подобъект JSON по указанному пути в виде
|
Примечание
Операторы извлечения полей/элементов/путей возвращают NULL, а не вызывают ошибку, если JSON-ввод не имеет правильной структуры для соответствия запросу; например, если такого ключа или элемента массива не существует.
Существуют дополнительные операторы только для типа jsonb
, как показано в Таблица 9.46.
Раздел 8.14.4 описывает, как эти операторы могут быть использованы для эффективного поиска индексированных данных типа jsonb
.
Таблица 9.46. Дополнительные операторы jsonb
Оператор Описание Пример(ы) |
---|
Содержит ли первое значение JSON второе? (См. Раздел 8.14.3 для получения подробной информации о содержании).
|
Содержится ли первое значение JSON во втором?
|
Существует ли текстовая строка в качестве ключа верхнего уровня или элемента массива в значении JSON?
|
Существуют ли какие-либо строки в массиве текста в качестве ключей верхнего уровня или элементов массива?
|
Существуют ли все строки в массиве текста в качестве ключей верхнего уровня или элементов массива?
|
Конкатенирует два значения
Чтобы добавить массив в другой массив как один элемент, оберните его в дополнительный слой массива, например:
|
Удаляет ключ (и его значение) из JSON-объекта или соответствующие строковые значения из JSON-массива.
|
Удаляет все совпадающие ключи или элементы массива из левого операнда.
|
Удаляет элемент массива с указанным индексом (отрицательные целые числа считаются с конца). Выдает ошибку, если значение JSON не является массивом.
|
Удаляет поле или элемент массива по указанному пути, где элементы пути могут быть ключами полей или индексами массива.
|
Возвращает ли JSON-путь какой-либо элемент для указанного значения JSON?
|
Возвращает результат проверки предиката JSON-пути для указанного значения JSON. Учитывается только первый элемент результата. Если результат не является логическим значением, то возвращается
|
Примечание
Операторы jsonpath
@?
и @@
подавляют следующие ошибки: отсутствие поля объекта или элемента массива, неожиданный тип элемента JSON, ошибки даты и числа. Описанные ниже функции, связанные с jsonpath
, также могут быть настроены на подавление этих типов ошибок. Это поведение может быть полезным при поиске коллекций JSON-документов с различной структурой.
Таблица 9.47 показывает функции, которые доступны для создания значений json
и jsonb
.
Таблица 9.47. Функции создания JSON
Функция Описание Пример(ы) |
---|
Преобразует любое SQL значение в
|
Преобразует SQL-массив в JSON-массив. Поведение аналогично функции
|
Преобразует составное значение SQL в объект JSON. Поведение аналогично функции
|
Создает, возможно, гетерогенный JSON-массив из списка аргументов переменной длины. Каждый аргумент преобразуется согласно функции
|
Создает JSON-объект из списка переменных аргументов. По соглашению,
список аргументов состоит из чередующихся ключей и значений. Ключевые
аргументы приводятся к типу text; аргументы значений преобразуются
согласно функциям
|
Создает JSON-объект из текстового массива. Массив должен иметь либо ровно одно измерение с четным количеством элементов, в этом случае они рассматриваются как чередующиеся пары ключ/значение, либо два измерения, так что каждый внутренний массив имеет ровно два элемента, которые рассматриваются как пара ключ/значение. Все значения преобразуются в JSON-строки.
|
Эта форма функции
|
Таблица 9.48 показывает функции, доступные для обработки значений json
и jsonb
.
Таблица 9.48. Функции обработки JSON
Функция Описание Пример(ы) |
---|
Расширяет верхний уровень JSON-массива в набор JSON-значений.
value ----------- 1 true [2,false]
|
Расширяет верхний уровень JSON-массива в набор значений
value ----------- foo bar
|
Возвращает количество элементов в массиве JSON верхнего уровня.
|
Расширяет верхний уровень JSON-объекта в набор пар ключ/значение.
key | value -----+------- a | "foo" b | "bar"
|
Расширяет верхний уровень JSON-объекта в набор пар ключ/значение.
Возвращаемые значения
key | value -----+------- a | foo b | bar
|
Извлекает подобъект JSON по указанному пути.
(Это функционально эквивалентно оператору
|
Извлекает подобъект JSON по указанному пути в виде
|
Возвращает набор ключей в объекте JSON верхнего уровня.
json_object_keys ------------------ f1 f2
|
Расширяет объект JSON верхнего уровня до строки, имеющей составной тип аргумента Для преобразования значения JSON в SQL тип выходной колонки применяются следующие правила последовательно:
В то время как приведенный ниже пример использует постоянное значение JSON, типичное использование будет заключаться в ссылке на столбец
a | b | c ---+-----------+------------- 1 | {2,"a b"} | (4,"a b c")
|
Расширяет верхний уровень JSON-массива объектов до набора строк, имеющих
составной тип аргумента
a | b ---+--- 1 | 2 3 | 4
|
Расширяет объект JSON верхнего уровня до строки, имеющей составной тип, определенный с помощью предложения
a | b | c | d | r ---+---------+---------+---+--------------- 1 | [1,2,3] | {1,2,3} | | (123,"a b c")
|
Расширяет верхний уровень JSON-массива объектов до набора строк, имеющих
составной тип, определенный с помощью предложения
a | b ---+----- 1 | foo 2 |
|
Возвращает
|
Если
|
Возвращает
|
Удаляет все поля объекта, которые имеют значение null из заданного JSON значения, рекурсивно. Значения null, которые не являются полями объекта, остаются нетронутыми.
|
Проверяет, возвращает ли JSON-путь какой-либо элемент для указанного JSON-значения.
Если указан аргумент
|
Возвращает результат проверки предиката JSON-пути для указанного значения JSON. Учитывается только первый элемент результата. Если результат не является логическим значением, то возвращается
|
Возвращает все элементы JSON, возвращаемые JSON-путем для указанного JSON-значения.
Необязательные аргументы
jsonb_path_query ------------------ 2 3 4
|
Возвращает все элементы JSON, возвращаемые JSON-путем для указанного JSON-значения, в виде JSON-массива.
Необязательные аргументы
|
Возвращает первый элемент JSON, возвращаемый JSON-путем для указанного JSON-значения. Возвращает
|
Эти функции действуют так же, как и их аналоги, описанные выше без суффикса
|
Преобразует заданное значение JSON в красиво отформатированный текст с отступами.
[ { "f1": 1, "f2": null }, 2 ]
|
Возвращает тип верхнего уровня значения JSON в виде текстовой строки.
Возможные типы:
|
9.16.2. Язык SQL/JSON Path
SQL/JSON путь выражения определяют элементы, которые должны быть извлечены из JSON данных, аналогично выражениям XPath, используемым для доступа к XML в SQL. В Tantor SE путь выражения реализованы в виде типа данных jsonpath
и могут использовать любые элементы, описанные в Раздел 8.14.7.
Функции и операторы запросов JSON передают предоставленное выражение пути в движок пути для оценки. Если выражение соответствует запрашиваемым данным JSON, возвращается соответствующий элемент JSON или набор элементов. Выражения пути записываются на языке SQL/JSON path и могут включать арифметические выражения и функции.
Выражение пути состоит из последовательности элементов, разрешенных
типом данных 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-объектам:
key
$.track.segments
Для получения содержимого массива обычно используется оператор [*]
. Например, следующий путь вернет координаты местоположения для всех доступных сегментов трека:
$.track.segments[*].location
Чтобы вернуть координаты только первого сегмента, вы можете указать соответствующий индекс в операторе доступа []
. Помните, что индексы массива JSON начинаются с 0:
$.track.segments[0].location
Результат каждого шага вычисления пути может быть обработан одним или несколькими операторами и методами jsonpath
, перечисленными в Раздел 9.16.2.2. Каждое имя метода должно предшествовать точке. Например, вы можете получить размер массива:
$.track.segments.size()
Больше примеров использования операторов и методов jsonpath
внутри выражений пути приведены ниже в Раздел 9.16.2.2.
При определении пути вы также можете использовать одно или несколько выражений фильтра, которые работают аналогично предложение WHERE
в SQL. Выражение фильтра начинается с вопросительного знака и содержит условие в скобках:
? (condition
)
Выражения фильтрации должны быть написаны сразу после шага оценки пути, к которому они должны применяться. Результат этого шага фильтруется таким образом, чтобы включать только те элементы, которые удовлетворяют заданному условию. SQL/JSON определяет трехзначную логику, поэтому условие может быть true
, false
или unknown
. Значение unknown
играет ту же роль, что и SQL NULL
и может быть проверено с помощью предиката is unknown
. Дальнейшие шаги оценки пути используют только те элементы, для которых выражение фильтрации вернуло true
.
Все функции и операторы, которые могут использоваться в выражениях фильтра, перечислены в Таблица 9.50. Внутри выражения фильтра переменная @
обозначает значение, которое фильтруется (т.е. один результат предыдущего шага пути). Вы можете использовать операторы доступа после @
для извлечения компонентных элементов.
Например, предположим, что нужно получить все значения пульса, превышающие 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()
Это выражение возвращает размер трека, если он содержит сегменты с высокими значениями пульса, или пустую последовательность в противном случае.
Реализация Tantor SE языка SQL/JSON path имеет следующие отклонения от стандарта SQL/JSON:
Выражение пути может быть логическим предикатом, хотя стандарт SQL/JSON разрешает предикаты только в фильтрах. Это необходимо для реализации оператора
@@
. Например, следующее выражениеjsonpath
является допустимым в Tantor SE:$.track.segments[*].HR < 70
В
like_regex
фильтрах есть небольшие различия в интерпретации шаблонов регулярных выражений, как описано в Раздел 9.16.2.3.
9.16.2.1. Строгий и Нестрогий режимы
Когда вы запрашиваете данные JSON, выражение пути может не соответствовать фактической структуре данных JSON. Попытка доступа к несуществующему члену объекта или элементу массива приводит к структурной ошибке. У выражений пути SQL/JSON есть два режима обработки структурных ошибок:
lax (по умолчанию) — движок пути неявно адаптирует запрашиваемые данные к указанному пути. Все оставшиеся структурные ошибки подавляются и преобразуются в пустые SQL/JSON последовательности.
strict — если происходит структурная ошибка, возникает ошибка.
Режим lax облегчает сопоставление структуры JSON-документа и пути выражения, если данные JSON не соответствуют ожидаемой схеме. Если операнд не соответствует требованиям определенной операции, он может быть автоматически обернут в SQL/JSON-массив или распакован путем преобразования его элементов в SQL/JSON-последовательность перед выполнением этой операции. Кроме того, операторы сравнения автоматически распаковывают свои операнды в режиме lax, поэтому вы можете сравнивать SQL/JSON-массивы "из коробки". Массив размером 1 считается равным своему единственному элементу. Автоматическое распаковывание не выполняется только в случае:
Выражение пути содержит методы
type()
илиsize()
, которые возвращают тип и количество элементов в массиве соответственно.Запрошенные данные JSON содержат вложенные массивы. В этом случае, только внешний массив распаковывается, в то время как все внутренние массивы остаются неизменными. Таким образом, неявное распаковывание может происходить только на один уровень вниз в каждом шаге оценки пути.
Например, при запросе данных GPS, перечисленных выше, вы можете абстрагироваться от того факта, что они хранят массив сегментов при использовании режима "lax":
lax $.track.segments.location
В строгом режиме указанный путь должен точно соответствовать структуре запрашиваемого JSON-документа, чтобы вернуть элемент SQL/JSON, поэтому использование этого выражения пути вызовет ошибку. Чтобы получить тот же результат, что и в режиме неполной проверки, необходимо явно распаковать массив segments
:
strict $.track.segments[*].location
Доступ к .**
может привести к неожиданным результатам при использовании режима lax. Например, следующий запрос выбирает каждое значение HR
дважды:
lax $.**.HR
Это происходит потому, что доступ к .**
выбирает как массив segments
, так и каждый из его элементов, в то время как доступ к .HR
автоматически распаковывает массивы при использовании режима lax. Чтобы избежать неожиданных результатов, рекомендуется использовать доступ .**
только в строгом режиме. Следующий запрос выбирает каждое значение HR
только один раз:
strict $.**.HR
9.16.2.2. Операторы и методы SQL/JSON Path
Таблица 9.49 показывает операторы и методы, доступные в jsonpath
. Обратите внимание, что унарные операторы и методы могут применяться к нескольким значениям, полученным из предыдущего шага пути, в то время как бинарные операторы (сложение и т. д.) могут применяться только к одному значению.
Таблица 9.49. jsonpath
Операторы и методы
Оператор/Метод Описание Пример(ы) |
---|
Дополнение
|
Унарный плюс (без операции); в отличие от сложения, он может выполняться для нескольких значений
|
Вычитание
|
Отрицание; в отличие от вычитания, это может выполняться для нескольких значений
|
Умножение
|
Раздел
|
Модуло (остаток)
|
Тип элемента JSON (см. функцию
|
Размер элемента JSON (количество элементов массива или 1, если это не массив)
|
Приблизительное число с плавающей запятой, преобразованное из числа или строки JSON
|
Ближайшее целое число, большее или равное заданному числу
|
Ближайшее целое число, меньшее или равное данному числу
|
Абсолютное значение данного числа
|
Значение даты/времени, преобразованное из строки
|
Значение даты/времени, преобразованное из строки с использованием указанного шаблона
|
Массив пар ключ-значение объекта, представленный в виде массива объектов, содержащих три поля:
|
Примечание
Тип результата методов datetime()
и
datetime(
может быть template
)date
, timetz
, time
,
timestamptz
или timestamp
.
Оба метода определяют свой тип результата динамически.
Метод datetime()
последовательно пытается сопоставить входную строку с форматами ISO для типов данных date
, timetz
, time
, timestamptz
и timestamp
. Он останавливается на первом совпадающем формате и возвращает соответствующий тип данных.
Метод datetime(
определяет тип результата в соответствии с полями, используемыми в предоставленной строке шаблона.
template
)
Методы datetime()
и
datetime(
используют те же правила разбора, что и функция SQL template
)to_timestamp
(см. Раздел 9.8), с тремя исключениями. Во-первых, эти методы не позволяют несоответствующие шаблону образцы. Во-вторых, в строке шаблона разрешены только следующие разделители: знак минуса, точка, косая черта (слэш), запятая, апостроф, точка с запятой, двоеточие и пробел. В-третьих, разделители в строке шаблона должны точно соответствовать входной строке.
Если требуется сравнить различные типы даты/времени, применяется неявное преобразование. Значение типа date
может быть приведено к типам timestamp
или timestamptz
, тип timestamp
может быть приведен к типу timestamptz
, а тип time
- к типу timetz
. Однако все эти преобразования, кроме первого, зависят от текущей настройки TimeZone, и поэтому могут выполняться только внутри функций jsonpath
, поддерживающих часовые пояса.
Таблица 9.50 показывает доступные элементы выражения фильтра.
Таблица 9.50. jsonpath
Элементы выражения фильтрации
Предикат/Значение Описание Пример(ы) |
---|
Сравнение на равенство (этот оператор, а также другие операторы сравнения, работают со всеми скалярными значениями JSON)
|
Сравнение неравенства
|
Сравнение меньше чем
|
Сравнение "меньше или равно"
|
Сравнение больше чем
|
Сравнение "больше или равно"
|
Константа JSON
|
JSON константа
|
JSON константа
|
Логическое И
|
Логическое ИЛИ
|
Логическое НЕТ
|
Проверяет, является ли логическое условие
|
Проверяет, соответствует ли первый операнд регулярному выражению, заданному вторым операндом, с возможными модификациями, описанными строкой символов
|
Проверяет, является ли второй операнд начальным подстрокой первого операнда.
|
Проверяет, соответствует ли выражение пути хотя бы одному элементу SQL/JSON.
Возвращает
|
9.16.2.3. SQL/JSON Регулярные выражения
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, так как он преобразует буквы флагов XQuery
так, чтобы соответствовать ожиданиям POSIX-движка.
Имейте в виду, что аргумент шаблона функции like_regex
является строковым литералом JSON-пути, написанным в соответствии с правилами, указанными в
Раздел 8.14.7. Это означает, что в частности, любые
обратные косые черты, которые нужно использовать в регулярном выражении, должны быть удвоены.
Например, чтобы сопоставить строковые значения корневого документа, содержащие
только цифры:
$.* ? (@ like_regex "^\\d+$")