9.16. Функции и операторы JSON #
В этом разделе описываются:
функции и операторы, предназначенные для работы с данными JSON
язык путей SQL/JSON
Postgres Pro реализует модель данных SQL/JSON, обеспечивая встроенную поддержку типов данных JSON в среде SQL. В этой модели данные представляются последовательностями элементов. Каждый элемент может содержать скалярные значения 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, поддерживаемые в Postgres Pro, описаны в Разделе 8.14.
9.16.1. Обработка и создание данных JSON #
Примечание
Функции, работающие с JSONB, не принимают символы '\u0000'
. Чтобы избежать ошибок и заменять их на лету, необходимо указать символ Unicode в параметре конфигурации unicode_nul_character_replacement_in_jsonb.
В Таблице 9.45 показаны имеющиеся операторы для работы с данными JSON (см. Раздел 8.14). Кроме них для типа jsonb
, но не для json
, определены обычные операторы сравнения, показанные в Таблице 9.1. Они следуют правилам упорядочивания для операций 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-объект по заданному пути в виде значения
|
Примечание
Если структура входного JSON не соответствует запросу, например указанный ключ или элемент массива отсутствует, операторы извлечения поля/элемента/пути не выдают ошибку, а возвращают NULL.
Некоторые из следующих операторов существуют только для 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-объект из переменного списка аргументов. По соглашению в этом списке перечисляются по очереди ключи и значения. Аргументы, задающие ключи, приводятся к текстовому типу, а аргументы-значения преобразуются методом
|
Создаёт объект JSON из всех заданных пар ключ/значение или пустой объект, если ни одна пара не задана. В аргументе
|
Формирует объект JSON из текстового массива. Этот массив должен иметь либо одну размерность с чётным числом элементов (в этом случае они воспринимаются как чередующиеся ключи/значения), либо две размерности и при этом каждый внутренний массив содержит ровно два элемента, которые воспринимаются как пара ключ/значение. Все значения преобразуются в строки JSON.
|
Эта форма
|
Преобразует выражение, заданное в виде строки типа
|
Преобразует заданное скалярное значение SQL в скалярное значение JSON. Если передаётся NULL, возвращается SQL NULL. Если передаётся число или логическое значение, возвращается соответствующее числовое или логическое значение JSON. Для любого другого значения возвращается строка JSON.
|
Преобразует выражение SQL/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).
key | value -----+------- a | "foo" b | "bar" |
Разворачивает JSON-объект верхнего уровня в набор пар ключ/значение (key/value). Возвращаемые значения будут иметь тип
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 | |
Возвращает объект
|
Если значение
|
Возвращает объект
|
Удаляет из данного значения JSON все поля объектов, имеющие значения null, на всех уровнях вложенности. Значения null, не относящиеся к полям объектов, сохраняются без изменений.
|
Проверяет, есть ли в заданном значении JSON какой-либо элемент, соответствующий пути JSON. В случае присутствия аргумента
|
Возвращает результат проверки предиката пути JSON для заданного значения JSON. При этом учитывается только первый элемент результата. Если результат не является логическим, возвращается
|
Возвращает все элементы JSON, полученные по указанному пути для заданного значения JSON. Дополнительные аргументы
jsonb_path_query ------------------ 2 3 4 |
Возвращает все элементы JSON, полученные по указанному пути для заданного значения JSON, в виде JSON-массива. Дополнительные аргументы
|
Возвращает первый элемент JSON, полученный по указанному пути для заданного значения JSON, либо NULL, если этому пути не соответствуют никакие элементы. Дополнительные аргументы
|
Эти функции работают подобно их двойникам без суффикса
|
Преобразует данное значение JSON в визуально улучшенное текстовое представление с отступами.
[ { "f1": 1, "f2": null }, 2 ] |
Возвращает тип значения на верхнем уровне JSON в виде текстовой строки. Возможные типы:
|
В Таблице 9.50 описаны функции SQL/JSON, которые можно использовать для обращения к данным JSON.
Примечание
Пути SQL/JSON можно применять только к типу jsonb
, поэтому аргумент элемент_контекста
этих функций, возможно, потребуется привести к типу jsonb
.
Таблица 9.50. Функции запросов SQL/JSON
9.16.2. JSON_TABLE #
json_table
— это функция SQL/JSON, которая обрабатывает данные JSON и выдаёт результаты в виде реляционного представления, к которому можно обращаться как к обычной таблице SQL. Использовать json_table
можно только внутри предложения FROM
оператора SELECT
.
Принимая данные JSON, функция json_table
обрабатывает выражение пути и извлекает часть представленных данных, которая будет использоваться в качестве шаблона строк для создаваемого представления. Каждый элемент SQL/JSON на верхнем уровне шаблона строк служит источником для отдельной строки в создаваемом реляционном представлении.
Для разделения шаблона строк на столбцы в функции json_table
применяется предложение COLUMNS
, определяющее схему создаваемого представления. В этом предложении для каждого создаваемого столбца задаётся отдельное выражение пути, обрабатывающее шаблон строк, извлекающее элемент JSON и возвращающее его в виде отдельного значения SQL для данного столбца. Если требуемое значение находится на вложенном уровне шаблона строк, его можно извлечь, используя вложенное предложение NESTED PATH
. При объединении столбцов, возвращаемых NESTED PATH
, в создаваемом представлении могут добавиться несколько новых строк. Такие строки называются дочерними строками, а строка, которая их создаёт, — родительской строкой.
Строки, формируемые функцией JSON_TABLE
, соединяются как последующие (LATERAL
) со строкой, из которой они сформированы, поэтому нет необходимости явно соединять создаваемое представление с исходной таблицей, содержащей данные JSON. При этом, используя предложение PLAN
, можно определить, как соединять столбцы, которые возвращает NESTED PATH
.
Каждое предложение NESTED PATH
может создать один или несколько столбцов. Столбцы, созданные NESTED PATH
на одном уровне, считаются соседними; при этом столбцы, созданные вложенным выражением NESTED PATH
, считаются потомками столбца, сформированного другим выражением NESTED PATH
или выражением строки на более высоком уровне. При формировании результата сначала вместе составляются соседние столбцы, а после этого полученные строки соединяются с родительской строкой.
Синтаксис:
JSON_TABLE (элемент_контекста
,выражение_пути
[ASимя_пути_json
] [PASSING {значение
ASимя_переменной
} [, ...]] COLUMNS (столбец_таблицы_json
[, ...] ) [{ERROR
|EMPTY
}ON ERROR
] [PLAN (план_таблицы_json
) | PLAN DEFAULT ( { INNER | OUTER } [, { CROSS | UNION }] | { CROSS | UNION } [, { INNER | OUTER }] )] ) Здесьстолбец_таблицы_json
:имя
тип
[PATHописание_пути_json
] [{ WITHOUT | WITH { CONDITIONAL | [UNCONDITIONAL] } } [ARRAY] WRAPPER] [{ KEEP | OMIT } QUOTES [ON SCALAR STRING]] [{ ERROR | NULL | DEFAULTвыражение
} ON EMPTY] [{ ERROR | NULL | DEFAULTвыражение
} ON ERROR] |имя
тип
FORMATпредставление_json
[PATHописание_пути_json
] [{ WITHOUT | WITH { CONDITIONAL | [UNCONDITIONAL] } } [ARRAY] WRAPPER] [{ KEEP | OMIT } QUOTES [ON SCALAR STRING]] [{ ERROR | NULL | EMPTY { ARRAY | OBJECT } | DEFAULTвыражение
} ON EMPTY] [{ ERROR | NULL | EMPTY { ARRAY | OBJECT } | DEFAULTвыражение
} ON ERROR] |имя
тип
EXISTS [PATHописание_пути_json
] [{ ERROR | TRUE | FALSE | UNKNOWN } ON ERROR] | NESTED PATHописание_пути_json
[ASимя_пути
] COLUMNS (столбец_таблицы_json
[, ...] ) |имя
FOR ORDINALITY здесьплан_таблицы_json
:имя_пути_json
[{ OUTER | INNER }первичный_план_таблицы_json
] |первичный_план_таблицы_json
{ UNIONпервичный_план_таблицы_json
} [...] |первичный_план_таблицы_json
{ CROSSпервичный_план_таблицы_json
} [...] здесьпервичный_план_таблицы_json
:имя_пути_json
| (план_таблицы_json
)
Каждый элемент синтаксиса описан ниже более подробно.
-
элемент_контекста
,выражение_пути
[AS
имя_пути_json
] [PASSING
{значение
AS
имя_переменной
} [, ...]] Входные данные для запроса, выражение пути JSON, определяющее запрос, и необязательное предложение
PASSING
, которое может предоставлять значения данных длявыражения_пути
. Результат обработки входных данных называется шаблоном строк. Шаблон строк используется в качестве источника для значений строк в создаваемом представлении.COLUMNS
(столбец_таблицы_json
[, ...] )Предложение
COLUMNS
, определяющее схему создаваемого представления. В этом предложении должны указываться все столбцы, в которые будут помещаться элементы SQL/JSON. Выражениестолбец_таблицы_json
имеет следующие варианты синтаксиса:-
имя
тип
[PATH
описание_пути_json
] Вставляет один элемент SQL/JSON во все строки с указанным столбцом.
Если заданное выражение
PATH
вычисляется, столбец заполняется сформированными элементами SQL/JSON (по одному в строке). Если выражениеPATH
опускается, функцияJSON_TABLE
вычисляет выражение пути$.
, гдеимя
имя
— указанное имя столбца. В этом случае имя столбца должно соответствовать одному из ключей в элементе SQL/JSON, созданном шаблоном строк.Также можно добавить предложения
ON EMPTY
иON ERROR
, чтобы определить, как обрабатывать отсутствующие значения или структурные ошибки. ПредложенияWRAPPER
иQUOTES
можно использовать только с типами JSON, массивами и составными типами. Эти предложения имеют тот же синтаксис и семантику, что и вjson_value
иjson_query
.-
имя
тип
FORMAT
представление_json
[PATH
описание_пути_json
] Создаёт столбец и вставляет составной элемент SQL/JSON во все строки с указанным столбцом.
Если заданное выражение
PATH
вычисляется, столбец заполняется сформированными элементами SQL/JSON (по одному в строке). Если выражениеPATH
опускается, функцияJSON_TABLE
вычисляет выражение пути$.
, гдеимя
имя
— указанное имя столбца. В этом случае имя столбца должно соответствовать одному из ключей в элементе SQL/JSON, созданном шаблоном строк.Также можно добавить предложения
WRAPPER
,QUOTES
,ON EMPTY
иON ERROR
, чтобы определить дополнительные параметры для возвращаемых элементов SQL/JSON. Эти предложения имеют тот же синтаксис и семантику, что и вjson_query
.-
имя
тип
EXISTS
[PATH
описание_пути_json
] Создаёт столбец и вставляет логический элемент во все строки с указанным столбцом.
Если заданное выражение
PATH
вычисляется, проводится проверка того, были ли получены соответствующие элементы SQL/JSON, и столбец заполняется логическими значениями (по одному в каждой строке). Для заданного типаtype
должно существовать приведение изboolean
. Если выражениеPATH
опускается, функцияJSON_TABLE
вычисляет выражение пути$.
, гдеимя
имя
— указанное имя столбца.Также можно добавить предложение
ON ERROR
, чтобы определить поведение при ошибке. Это предложение имеет тот же синтаксис и семантику, что и вjson_exists
.NESTED PATH
описание_пути_json
[AS
имя_пути_json
]COLUMNS
(столбец_таблицы_json
[, ...] )Извлекает элементы SQL/JSON из вложенных уровней шаблона строк, создаёт один или несколько столбцов, как определено во вложенном предложении
COLUMNS
, и вставляет извлечённые элементы SQL/JSON во все строки с этими столбцами. Выражениестолбец_таблицы_json
во вложенном предложенииCOLUMNS
имеет тот же синтаксис, что и в родительском предложенииCOLUMNS
.Синтаксис
NESTED PATH
является рекурсивным, поэтому, вкладывая предложенияNESTED PATH
одно в другое, можно опускаться ниже от уровня к уровню. Это позволяет разложить иерархию объектов и массивов JSON в одном вызове функции, а не связывать несколько выраженийJSON_TABLE
в операторе SQL.Используя предложение
PLAN
, можно определить, как объединять столбцы, возвращаемые предложениямиNESTED PATH
.-
имя
FOR ORDINALITY
Добавляет столбец, обеспечивающий последовательную нумерацию строк. В таблице может быть только один столбец нумерации. Нумерация строк начинается с единицы. Для дочерних строк, сформированных предложениями
NESTED PATH
, повторяется номер родительской строки.
-
-
AS
имя_пути_json
Необязательный параметр
имя_пути_json
служит идентификатором заданного параметраописание_пути_json
. Имя пути должно быть уникальным и отличаться от имён столбцов. Когда применяется предложениеPLAN
, необходимо задать имена для всех путей, включая шаблон строк. Имена путей в предложенииPLAN
не могут повторяться.PLAN
(план_таблицы_json
)Определяет, как соединять данные, возвращаемые предложениями
NESTED PATH
, с создаваемым представлением.Соединять столбцы, реализуя отношения родитель/потомок, можно следующими способами:
-
INNER
Используйте
INNER JOIN
, чтобы родительская строка была исключена из вывода, если для неё не нашлось дочерних строк при объединении с данными, возвращённымиNESTED PATH
.-
OUTER
Используйте
LEFT OUTER JOIN
, чтобы родительская строка всегда включалась в вывод, даже если для неё не нашлось дочерних строк при объединении с данными, возвращённымиNESTED PATH
. Если соответствующие значения отсутствуют, в дочерние столбцы будут вставлены значения NULL.По умолчанию для соединения столбцов используется этот вариант.
Соединять соседние столбцы можно следующими способами:
-
UNION
Сгенерировать одну строку для каждого значения отдельного соседнего столбца. Соседи данного столбца при этом заполняются значениями NULL.
Этот вариант выбирается по умолчанию для соединения соседних столбцов.
-
CROSS
Сгенерировать одну строку для каждой комбинации значений из соседних столбцов.
-
PLAN DEFAULT
(
)OUTER | INNER
[,UNION | CROSS
]Эти указания могут также задаваться в обратном порядке. В этом случае
INNER
илиOUTER
определяет план соединения родительских/дочерних столбцов, аUNION
илиCROSS
влияет на объединение соседних столбцов. ФормаPLAN DEFAULT
переопределяет план по умолчанию для всех столбцов сразу. Несмотря на то, что в формеPLAN DEFAULT
имена путей не указываются, для соответствия стандарту SQL/JSON имена должны задаваться для всех путей, если используется предложениеPLAN
.Использовать
PLAN DEFAULT
проще, чем указывать полныйPLAN
, и зачастую этого достаточно для получения желаемого результата.
Примеры
В этих примерах будет использоваться следующая небольшая таблица, содержащая данные JSON:
CREATE TABLE my_films ( js jsonb ); INSERT INTO my_films VALUES ( '{ "favorites" : [ { "kind" : "comedy", "films" : [ { "title" : "Bananas", "director" : "Woody Allen"}, { "title" : "The Dinner Game", "director" : "Francis Veber" } ] }, { "kind" : "horror", "films" : [ { "title" : "Psycho", "director" : "Alfred Hitchcock" } ] }, { "kind" : "thriller", "films" : [ { "title" : "Vertigo", "director" : "Alfred Hitchcock" } ] }, { "kind" : "drama", "films" : [ { "title" : "Yojimbo", "director" : "Akira Kurosawa" } ] } ] }');
Составьте запрос, читающий из таблицы my_films
данные о фильмах и создающий представление, в котором жанр, название и режиссёр фильма распределяются по отдельным столбцам:
SELECT jt.* FROM my_films, JSON_TABLE ( js, '$.favorites[*]' COLUMNS ( id FOR ORDINALITY, kind text PATH '$.kind', NESTED PATH '$.films[*]' COLUMNS ( title text PATH '$.title', director text PATH '$.director'))) AS jt; ----+----------+------------------+------------------- id | kind | title | director ----+----------+------------------+------------------- 1 | comedy | Bananas | Woody Allen 1 | comedy | The Dinner Game | Francis Veber 2 | horror | Psycho | Alfred Hitchcock 3 | thriller | Vertigo | Alfred Hitchcock 4 | drama | Yojimbo | Akira Kurosawa (5 rows)
Найдите режиссёра, который снимал фильмы в двух разных жанрах:
SELECT director1 AS director, title1, kind1, title2, kind2 FROM my_films, JSON_TABLE ( js, '$.favorites' AS favs COLUMNS ( NESTED PATH '$[*]' AS films1 COLUMNS ( kind1 text PATH '$.kind', NESTED PATH '$.films[*]' AS film1 COLUMNS ( title1 text PATH '$.title', director1 text PATH '$.director') ), NESTED PATH '$[*]' AS films2 COLUMNS ( kind2 text PATH '$.kind', NESTED PATH '$.films[*]' AS film2 COLUMNS ( title2 text PATH '$.title', director2 text PATH '$.director' ) ) ) PLAN (favs OUTER ((films1 INNER film1) CROSS (films2 INNER film2))) ) AS jt WHERE kind1 > kind2 AND director1 = director2; director | title1 | kind1 | title2 | kind2 ------------------+---------+----------+--------+-------- Alfred Hitchcock | Vertigo | thriller | Psycho | horror (1 row)
9.16.3. Язык путей SQL/JSON #
Выражения путей SQL/JSON определяют элементы, извлекаемые из данных JSON, подобно тому, как выражения XPath позволяют обращаться из SQL к XML. В Postgres Pro выражения путей представляются в виде типа данных jsonpath
и могут использовать любые элементы, описанные в Подразделе 8.14.7.
Операторы и функции запросов к 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
, перечисленными в Подразделе 9.16.3.2. Перед именем метода должна стоять точка. Например, так можно получить размер массива:
$.track.segments.size()
Другие примеры использования операторов и методов jsonpath
в выражениях пути приведены ниже в Подразделе 9.16.3.2.
Определяя путь, также можно использовать выражения фильтра, работающие подобно предложению WHERE
в SQL. Выражение фильтра начинается со знака вопроса и содержит условие в скобках:
? (условие
)
Выражения фильтра указываются сразу после шага вычисления пути, к которому они должны применяться. Результаты шага проходят через фильтр, и на выходе остаются только те элементы, которые удовлетворяют заданному условию. В SQL/JSON действует троичная логика, то есть результатом выражения может быть true
, false
или unknown
(неизвестность). Значение unknown
играет ту же роль, что и NULL
в SQL, и может быть проверено предикатом is unknown
. На последующих шагах вычисления пути будут обрабатываться только те элементы, для которых выражение фильтра выдало true
.
Функции и операторы, которые можно использовать в выражениях фильтра, перечислены в Таблице 9.52. Переменная @
в выражении фильтра представляет фильтруемое значение (результат предыдущего шага в пути). Для получения внутренних элементов этого значения вы можете добавить после @
операторы обращения.
Например, предположим, что вы хотите получить все показатели пульса, превышающие 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 в Postgres Pro имеет следующие отличия от стандарта SQL/JSON:
Выражение пути может быть булевым предикатом, хотя стандарт SQL/JSON допускает предикаты только в фильтрах. Это необходимо для реализации оператора
@@
. Например, следующее выражениеjsonpath
допускается в Postgres Pro:$.track.segments[*].HR < 70
Есть небольшие различия в интерпретации шаблонов регулярных выражений, используемых в фильтрах
like_regex
; имеющиеся особенности описаны в Подразделе 9.16.3.3.
9.16.3.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.16.3.2. Операторы и методы SQL/JSON #
В Таблице 9.51 показаны операторы и методы, поддерживаемые в значениях jsonpath
. Заметьте, что унарные операторы и методы могут применяться к множеству значений, полученных на предыдущем шаге пути, тогда как бинарные операторы (сложение и т. п.) применяются только к отдельным значениям.
Таблица 9.51. Операторы и методы jsonpath
Оператор/Метод Описание Пример(ы) |
---|
Сложение
|
Унарный плюс (нет операции); в отличие от сложения, он может итерационно применяться к множеству значений
|
Вычитание
|
Смена знака; в отличие от вычитания, этот оператор может итерационно применяться к множеству значений
|
Умножение
|
Деление
|
Остаток от деления
|
Тип элемента JSON (см.
|
Размер элемента JSON (число элементов в массиве либо 1, если это не массив)
|
Приблизительное число с плавающей точкой, преобразованное из строки или числа JSON
|
Ближайшее целое, большее или равное заданному числу
|
Ближайшее целое, меньшее или равное заданному числу
|
Модуль заданного числа (абсолютное значение)
|
Значение даты/времени, полученное из строки
|
Значение даты/времени, преобразованное из строки по шаблону
|
Пары ключ-значение, представленные в виде массива объектов со следующими тремя полями:
|
Примечание
Результирующим типом методов datetime()
и datetime(
может быть шаблон
)date
, timetz
, time
, timestamptz
или timestamp
. Эти два метода определяют тип своего результата автоматически.
Метод datetime()
пытается последовательно сопоставить поступившую на вход строку с ISO-форматами типов date
, timetz
, time
, timestamptz
и timestamp
. Встретив первый подходящий формат, он останавливается и возвращает соответствующий тип данных.
Метод datetime(
определяет результирующий тип в соответствии с полями заданного шаблона.шаблон
)
Методы datetime()
и datetime(
применяют те же правила разбора строки, что и SQL-функция шаблон
)to_timestamp
(см. Раздел 9.8), но с тремя исключениями. Во-первых, эти методы не позволяют использовать в шаблоне поля, которым не находится соответствие. Во-вторых, в шаблоне допускаются только следующие разделители: знак минуса, точка, косая черта, запятая, апостроф, точка с запятой, запятая и пробел. В-третьих, разделители в шаблоне должны в точности соответствовать входной строке.
Если требуется сравнить значения разных типов даты/времени, применяется неявное приведение типа. Значение date
может быть приведено к типу timestamp
или timestamptz
; timestamp
— к типу timestamptz
, а time
— к timetz
. Однако все эти приведения, кроме первого, зависят от текущего значения TimeZone и поэтому не могут выполняться в функциях jsonpath
, не учитывающих часовой пояс.
В Таблице 9.52 перечислены допустимые элементы выражения фильтра.
Таблица 9.52. Элементы выражения фильтра jsonpath
Предикат/значение Описание Пример(ы) |
---|
Проверка равенства (все операторы сравнения, включая этот, работают с любыми скалярными значениями JSON)
|
Проверка неравенства
|
Проверка «меньше»
|
Проверка «меньше или равно»
|
Проверка «больше»
|
Проверка «больше или равно»
|
JSON-константа
|
JSON-константа
|
JSON-константа
|
Логическое И
|
Логическое ИЛИ
|
Логическое НЕ
|
Проверяет, является ли
|
Проверяет, соответствует ли первый операнд регулярному выражению, которое задаёт второй операнд с необязательным аргументом
|
Проверяет, является ли второй операнд начальной подстрокой первого.
|
Проверяет, соответствует ли выражению пути минимум один элемент SQL/JSON. Возвращает
|
9.16.3.3. Регулярные выражения SQL/JSON #
Выражения путей SQL/JSON могут содержать фильтры like_regex
, позволяющие сопоставлять текст с регулярным выражением. Например, следующий запрос пути SQL/JSON выберет все строки в массиве, которые начинаются с английской гласной в любом регистре:
$[*] ? (@ like_regex "^[aeiou]" flag "i")
Необязательная строка flag
может содержать один или несколько следующих символов: i
, делающий поиск регистронезависимым, m
, допускающий сопоставление ^
и $
с переводами строк, s
, допускающий сопоставление .
с символом новой строки, и q
, берущий в кавычки весь шаблон (в результате производится простой поиск подстроки).
Стандарт SQL/JSON заимствует определение регулярных выражений от оператора LIKE_REGEX
, который, в свою очередь, реализуется по стандарту XQuery. Однако в Postgres Pro оператор 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.7. Это в частности означает, что каждую косую черту в регулярном выражении надо дублировать. Например, чтобы отобрать строковые значения, находящиеся на уровне корня документа и содержащие только цифры, нужно написать:
$.* ? (@ like_regex "^\\d+$")