9.16. Функции и операторы JSON#
9.16. Функции и операторы JSON #
Этот раздел описывает:
функции и операторы для обработки и создания данных JSON
язык SQL/JSON пути
Для обеспечения нативной поддержки типов данных JSON в среде SQL, Tantor BE реализует модель данных SQL/JSON. Эта модель включает последовательности элементов. Каждый элемент может содержать скалярные значения SQL, с дополнительным значением SQL/JSON null, и составные структуры данных, использующие массивы и объекты JSON. Модель является формализацией подразумеваемой модели данных в спецификации JSON RFC 7159.
SQL/JSON позволяет работать с данными JSON наряду с обычными данными SQL, с поддержкой транзакций, включая:
Загрузка данных JSON в базу данных и их хранение в обычных SQL-столбцах в виде строк символов или двоичных строк.
Генерация JSON объектов и массивов из реляционных данных.
Запрос данных JSON с использованием функций запроса SQL/JSON и выражений языка путей SQL/JSON.
Чтобы узнать больше о стандарте SQL/JSON, см. [sqltr-19075-6]. Для получения подробной информации о типах JSON, поддерживаемых в Tantor BE, см. Раздел 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. Некоторые функции в этой таблице имеют предложение RETURNING, которая указывает возвращаемый тип данных. Он должен быть одним из json, jsonb, bytea, строкового типа символов (text, char или varchar), или типа, который может быть приведен к json. По умолчанию возвращается тип json.
Таблица 9.47. Функции создания JSON
Функция Описание Пример(ы) |
|---|
|
Преобразует любое SQL значение в
|
Преобразует SQL-массив в JSON-массив. Поведение аналогично функции
|
Создает JSON массив либо из серии параметров
|
Преобразует составное значение SQL в объект JSON. Поведение аналогично функции
|
Создает, возможно, гетерогенный JSON-массив из списка аргументов переменной длины. Каждый аргумент преобразуется согласно функции
|
Создает JSON-объект из списка переменных аргументов. По соглашению,
список аргументов состоит из чередующихся ключей и значений. Ключевые
аргументы приводятся к типу text; аргументы значений преобразуются
согласно функциям
|
Создает JSON-объект из всех данных пар ключ/значение или пустой объект, если пары не заданы.
|
|
Создает JSON-объект из текстового массива. Массив должен иметь либо ровно одно измерение с четным количеством элементов, в этом случае они рассматриваются как чередующиеся пары ключ/значение, либо два измерения, так что каждый внутренний массив имеет ровно два элемента, которые рассматриваются как пара ключ/значение. Все значения преобразуются в JSON-строки.
|
Эта форма функции
|
Таблица 9.48 описывает возможности SQL/JSON для тестирования JSON.
Таблица 9.48. Функции тестирования SQL/JSON
Таблица 9.49 показывает функции, доступные для обработки значений json и jsonb.
Таблица 9.49. Функции обработки 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 BE путь выражения реализованы в виде типа данных 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.51. Внутри выражения фильтра переменная @ обозначает значение, которое фильтруется (т.е. один результат предыдущего шага пути). Вы можете использовать операторы доступа после @ для извлечения компонентных элементов.
Например, предположим, что нужно получить все значения пульса, превышающие 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 BE языка SQL/JSON path имеет следующие отклонения от стандарта SQL/JSON:
Выражение пути может быть логическим предикатом, хотя стандарт SQL/JSON разрешает предикаты только в фильтрах. Это необходимо для реализации оператора
@@. Например, следующее выражениеjsonpathявляется допустимым в Tantor BE:$.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.50 показывает операторы и методы, доступные в jsonpath. Обратите внимание, что унарные операторы и методы могут применяться к нескольким значениям, полученным из предыдущего шага пути, в то время как бинарные операторы (сложение и т. д.) могут применяться только к одному значению.
Таблица 9.50. 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.51 показывает доступные элементы выражения фильтра.
Таблица 9.51. 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+$")