8.14. Типы JSON#

8.14. Типы JSON

8.14. Типы JSON

Типы данных JSON предназначены для хранения данных JSON (JavaScript Object Notation), как указано в RFC 7159. Такие данные также могут быть сохранены как text, но типы данных JSON имеют преимущество в том, что они обеспечивают соблюдение правил JSON для каждого сохраненного значения. Кроме того, для данных, хранящихся в этих типах данных, доступны различные JSON-специфичные функции и операторы; см. Раздел 9.16.

Tantor SE предлагает два типа для хранения JSON данных: json и jsonb. Чтобы реализовать эффективные механизмы запросов для этих типов данных, Tantor SE также предоставляет тип данных jsonpath, описанный в Раздел 8.14.7.

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

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

В целом, большинство приложений должны предпочитать хранить данные в формате JSON как jsonb, если нет особых требований, таких как устаревшие предположения о порядке ключей объекта.

Спецификация RFC 7159 указывает, что JSON-строки должны быть закодированы в UTF8. Поэтому JSON-типы не могут строго соответствовать спецификации JSON, если кодировка базы данных не является UTF8. Попытки напрямую включить символы, которые не могут быть представлены в кодировке базы данных, завершатся неудачей; наоборот, символы, которые могут быть представлены в кодировке базы данных, но не в UTF8, будут разрешены.

RFC 7159 позволяет JSON-строкам содержать последовательности символов Unicode, обозначаемые с помощью \uXXXX. В функции ввода для типа json разрешены Unicode-последовательности независимо от кодировки базы данных и проверяются только на синтаксическую корректность (то есть наличие четырех шестнадцатеричных цифр после \u). Однако функция ввода для типа jsonb более строгая: она запрещает использование Unicode-последовательностей для символов, которые не могут быть представлены в кодировке базы данных. Тип jsonb также отклоняет \u0000 (потому что это не может быть представлено в типе text Tantor SE), и требует, чтобы любое использование пар суррогатных символов для обозначения символов вне основной многоязыковой плоскости Unicode было правильным. Допустимые Unicode-последовательности преобразуются в эквивалентный одиночный символ для хранения; это включает объединение пар суррогатных символов в один символ.

Примечание

Многие из описанных функций обработки JSON в Раздел 9.16 преобразуют символы Unicode в обычные символы и, следовательно, будут выбрасывать те же типы ошибок, описанные ранее, даже если их входные данные имеют тип json, а не jsonb. Тот факт, что функция ввода json не выполняет эти проверки, может рассматриваться как исторический артефакт, хотя она позволяет просто хранить (без обработки) символы Unicode JSON в кодировке базы данных, которая не поддерживает представленные символы.

При преобразовании текстового ввода JSON в тип jsonb, примитивные типы, описанные в RFC 7159, эффективно отображаются на собственные типы Tantor SE, как показано в таблице сопоставления типов json (см. ссылку Таблица 8.23). Поэтому существуют некоторые незначительные дополнительные ограничения на то, что является допустимыми данными типа jsonb, которые не применяются к типу json или к JSON в абстрактном смысле, соответствующие ограничениям на то, что может быть представлено базовым типом данных. В частности, jsonb будет отклонять числа, выходящие за пределы диапазона числовых данных типа numeric Tantor SE, в то время как json этого не делает. Такие ограничения, определенные реализацией, разрешены RFC7159. Однако на практике такие проблемы гораздо более вероятно возникают в других реализациях, так как обычно примитивный тип числа JSON представляется двойной точностью с плавающей запятой IEEE 754 (что явно предусмотрено и разрешено RFC 7159). При использовании JSON в качестве формата обмена данными с такими системами следует учитывать опасность потери числовой точности по сравнению с данными, изначально сохраненными в Tantor SE.

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

Таблица 8.23. Типы примитивов JSON и соответствующие типы в Tantor SE

Тип примитива JSONТип Tantor SEПримечания
stringtext\u0000 запрещен, также запрещены Unicode-последовательности, представляющие символы, недоступные в кодировке базы данных
numbernumericNaN и значения infinity запрещены
booleanbooleanПринимаются только строчные написания true и false
null(нет)SQL NULL - это другая концепция

8.14.1. Синтаксис ввода и вывода JSON

Синтаксис ввода/вывода для типов данных JSON соответствует спецификации в RFC 7159.

Следующие выражения json (или jsonb) являются допустимыми:

-- Simple scalar/primitive value
-- Primitive values can be numbers, quoted strings, true, false, or null
SELECT '5'::json;

-- Array of zero or more elements (elements need not be of same type)
SELECT '[1, 2, "foo", null]'::json;

-- Object containing pairs of keys and values
-- Note that object keys must always be quoted strings
SELECT '{"bar": "baz", "balance": 7.77, "active": false}'::json;

-- Arrays and objects can be nested arbitrarily
SELECT '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'::json;

Как уже упоминалось ранее, когда значение JSON вводится и затем выводится без дополнительной обработки, json выводит тот же текст, который был введен, в то время как jsonb не сохраняет семантически незначимые детали, такие как пробелы. Например, обратите внимание на различия здесь:

SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::json;
                      json
-------------------------------------------------
 {"bar": "baz", "balance": 7.77, "active":false}
(1 row)

SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::jsonb;
                      jsonb
--------------------------------------------------
 {"bar": "baz", "active": false, "balance": 7.77}
(1 row)

Одна семантически незначимая деталь, которую стоит отметить, заключается в том, что в типе jsonb числа будут выводиться в соответствии с поведением базового типа numeric. На практике это означает, что числа, введенные с использованием обозначения E, будут выводиться без него, например:

SELECT '{"reading": 1.230e-5}'::json, '{"reading": 1.230e-5}'::jsonb;
         json          |          jsonb
-----------------------+-------------------------
 {"reading": 1.230e-5} | {"reading": 0.00001230}
(1 row)

Однако, jsonb сохранит конечные дробные нули, как видно в этом примере, даже если они семантически несущественны для целей, таких как проверка равенства.

Для списка встроенных функций и операторов, доступных для создания и обработки значений JSON, см. Раздел 9.16.

8.14.2. Проектирование JSON-документов

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

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

8.14.3. jsonb Содержание и существование

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

-- Simple scalar/primitive values contain only the identical value:
SELECT '"foo"'::jsonb @> '"foo"'::jsonb;

-- The array on the right side is contained within the one on the left:
SELECT '[1, 2, 3]'::jsonb @> '[1, 3]'::jsonb;

-- Order of array elements is not significant, so this is also true:
SELECT '[1, 2, 3]'::jsonb @> '[3, 1]'::jsonb;

-- Duplicate array elements don't matter either:
SELECT '[1, 2, 3]'::jsonb @> '[1, 2, 2]'::jsonb;

-- The object with a single pair on the right side is contained
-- within the object on the left side:
SELECT '{"product": "PostgreSQL", "version": 9.4, "jsonb": true}'::jsonb @> '{"version": 9.4}'::jsonb;

-- The array on the right side is not considered contained within the
-- array on the left, even though a similar array is nested within it:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[1, 3]'::jsonb;  -- yields false

-- But with a layer of nesting, it is contained:
SELECT '[1, 2, [1, 3]]'::jsonb @> '[[1, 3]]'::jsonb;

-- Similarly, containment is not reported here:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"bar": "baz"}'::jsonb;  -- yields false

-- A top-level key and an empty object is contained:
SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"foo": {}}'::jsonb;

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

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

-- This array contains the primitive string value:
SELECT '["foo", "bar"]'::jsonb @> '"bar"'::jsonb;

-- This exception is not reciprocal -- non-containment is reported here:
SELECT '"bar"'::jsonb @> '["bar"]'::jsonb;  -- yields false

jsonb также имеет оператор existence, который является вариацией на тему содержания: он проверяет, появляется ли строка (заданная как значение text) в качестве ключа объекта или элемента массива на верхнем уровне значения jsonb. Эти примеры возвращают true, за исключением указанных случаев:

-- String exists as array element:
SELECT '["foo", "bar", "baz"]'::jsonb ? 'bar';

-- String exists as object key:
SELECT '{"foo": "bar"}'::jsonb ? 'foo';

-- Object values are not considered:
SELECT '{"foo": "bar"}'::jsonb ? 'bar';  -- yields false

-- As with containment, existence must match at the top level:
SELECT '{"foo": {"bar": "baz"}}'::jsonb ? 'bar'; -- yields false

-- A string is considered to exist if it matches a primitive JSON string:
SELECT '"foo"'::jsonb ? 'foo';

JSON-объекты лучше подходят для проверки наличия или содержания, когда вовлечено много ключей или элементов, потому что, в отличие от массивов, они внутренне оптимизированы для поиска и не требуют линейного поиска.

Подсказка

Поскольку JSON-контейнеры являются вложенными, соответствующий запрос может пропустить явное выбор подобъектов. Например, предположим, что у нас есть столбец doc, содержащий объекты на верхнем уровне, большинство из которых содержат поля tags, содержащие массивы подобъектов. Этот запрос находит записи, в которых подобъекты, содержащие и "term":"paris", и "term":"food", появляются, игнорируя любые такие ключи вне массива tags:

SELECT doc->'site_name' FROM websites
  WHERE doc @> '{"tags":[{"term":"paris"}, {"term":"food"}]}';

То же самое можно сделать, скажем,

SELECT doc->'site_name' FROM websites
  WHERE doc->'tags' @> '[{"term":"paris"}, {"term":"food"}]';

но такой подход менее гибкий и часто менее эффективный.

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

Различные операторы содержания и существования, а также все остальные операторы и функции JSON документированы в Раздел 9.16.

8.14.4. jsonb Индексирование

GIN индексы могут быть использованы для эффективного поиска ключей или пар ключ/значение, встречающихся в большом количестве документов jsonb (датумов). Предоставляются два класса операторов GIN, предлагающих различные компромиссы между производительностью и гибкостью.

Класс операторов GIN по умолчанию для jsonb поддерживает запросы с использованием операторов проверки наличия ключа ?, ?| и ?&, оператора содержания @> и операторов сопоставления jsonpath @? и @@. (Подробнее о семантике, реализуемой этими операторами, см. Таблица 9.46). Пример создания индекса с использованием этого класса операторов:

CREATE INDEX idxgin ON api USING GIN (jdoc);

Нестандартный класс операторов GIN jsonb_path_ops не поддерживает операторы проверки наличия ключа, но поддерживает операторы @>, @? и @@. Пример создания индекса с использованием этого класса операторов:

CREATE INDEX idxginp ON api USING GIN (jdoc jsonb_path_ops);

Рассмотрим пример таблицы, которая хранит JSON-документы, полученные из стороннего веб-сервиса, с задокументированной схемой определения. Типичный документ выглядит так:

{
    "guid": "9c36adc1-7fb5-4d5b-83b4-90356a46061a",
    "name": "Angela Barton",
    "is_active": true,
    "company": "Magnafone",
    "address": "178 Howard Place, Gulf, Washington, 702",
    "registered": "2009-11-07T08:53:22 +08:00",
    "latitude": 19.793713,
    "longitude": 86.513373,
    "tags": [
        "enim",
        "aliquip",
        "qui"
    ]
}

Мы храним эти документы в таблице с именем api, в столбце jsonb с именем jdoc. Если на этом столбце создан индекс GIN, запросы, подобные следующим, могут использовать индекс:

-- Find documents in which the key "company" has value "Magnafone"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"company": "Magnafone"}';

Однако индекс не может использоваться для запросов, подобных следующим, потому что, хотя оператор ? является индексируемым, он не применяется непосредственно к индексированному столбцу jdoc:

-- Find documents in which the key "tags" contains key or array element "qui"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc -> 'tags' ? 'qui';

Все же, с правильным использованием индексов выражений, вышеприведенный запрос может использовать индекс. Если часто выполняются запросы для определенных элементов в ключе "tags", то определение индекса вот таким образом может быть целесообразным:

CREATE INDEX idxgintags ON api USING GIN ((jdoc -> 'tags'));

Теперь, предложение WHERE jdoc -> 'tags' ? 'qui' будет распознано как применение индексируемого оператора ? к индексированному выражению jdoc -> 'tags'. (Более подробную информацию о выражениях-индексах можно найти в разделе Раздел 11.7).

Другой подход к запросам - это использование вложенности, например:

-- Find documents in which the key "tags" contains array element "qui"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qui"]}';

Простой индекс GIN на столбце jdoc может поддерживать этот запрос. Но обратите внимание, что такой индекс будет хранить копии каждого ключа и значения в столбце jdoc, в то время как индекс выражений из предыдущего примера хранит только данные, найденные под ключом tags. В то время как простой подход к индексированию гораздо более гибкий (поскольку он поддерживает запросы по любому ключу), целевые индексы выражений, скорее всего, будут меньше и быстрее для поиска, чем простой индекс.

GIN-индексы также поддерживают операторы @? и @@, которые выполняют сопоставление jsonpath. Примеры:

SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @? '$.tags[*] ? (@ == "qui")';

SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @@ '$.tags[*] == "qui"';

Для этих операторов индекс GIN извлекает предложения вида accessors_chain = constant из шаблона jsonpath и выполняет поиск по индексу на основе ключей и значений, указанных в этих предложениях. Цепочка аксессоров может включать .key, [*], и [index]. Операторный класс jsonb_ops также поддерживает аксессоры .* и .**, но операторный класс jsonb_path_ops - нет.

Хотя класс операторов jsonb_path_ops поддерживает только запросы с операторами @>, @? и @@, он имеет заметные преимущества производительности по сравнению с классом операторов по умолчанию jsonb_ops. Индекс jsonb_path_ops обычно значительно меньше, чем индекс jsonb_ops для тех же данных, и специфичность поиска лучше, особенно когда запросы содержат ключи, которые часто встречаются в данных. Поэтому операции поиска обычно выполняются лучше, чем с классом операторов по умолчанию.

Разница между техническими индексами GIN jsonb_ops и jsonb_path_ops заключается в том, что первый создает независимые элементы индекса для каждого ключа и значения в данных, в то время как второй создает элементы индекса только для каждого значения в данных. [7] В основном, каждый элемент индекса jsonb_path_ops представляет собой хеш-значение и ключ(и), ведущие к нему; например, для индексации {"foo": {"bar": "baz"}} будет создан один элемент индекса, включающий все три значения foo, bar и baz. Таким образом, запрос на содержание этой структуры приведет к крайне точному поиску по индексу; однако нет никакого способа узнать, появляется ли foo в качестве ключа. С другой стороны, индекс jsonb_ops создаст три элемента индекса, представляющих отдельно foo, bar и baz; затем для выполнения запроса на содержание он будет искать строки, содержащие все три элемента. Хотя индексы GIN могут выполнять такой поиск с использованием оператора AND достаточно эффективно, он все равно будет менее точным и медленнее, чем эквивалентный поиск с использованием jsonb_path_ops, особенно если имеется очень большое количество строк, содержащих любой из трех элементов индекса.

Одним из недостатков подхода jsonb_path_ops является отсутствие индексных записей для JSON-структур, не содержащих значения, например, {"a": {}}. Если требуется поиск документов, содержащих такую структуру, потребуется полное сканирование индекса, что довольно медленно. Поэтому jsonb_path_ops не подходит для приложений, которые часто выполняют такие поиски.

jsonb также поддерживает индексы btree и hash. Они обычно полезны только в том случае, если важно проверить равенство полных JSON-документов. Порядок btree для данных типа jsonb редко представляет большой интерес, но для полноты он следующий:

Object > Array > Boolean > Number > String > Null

Object with n pairs > object with n - 1 pairs

Array with n elements > array with n - 1 elements

Объекты с одинаковым количеством пар сравниваются в следующем порядке:

key-1, value-1, key-2 ...

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

{ "aa": 1, "c": 1} > {"b": 1, "d": 1}

Аналогично, массивы с одинаковым количеством элементов сравниваются в порядке:

element-1, element-2 ...

Примитивные значения JSON сравниваются с использованием тех же правил сравнения, что и для базового типа данных Tantor SE. Строки сравниваются с использованием сортировки базы данных по умолчанию.

8.14.5. jsonb Подсказка

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

UPDATE операторы могут использовать индексацию в SET разделе для изменения значений типа jsonb. Индексные пути должны быть доступны для всех затронутых значений, насколько они существуют. Например, путь val['a']['b']['c'] может быть пройден до c, если каждый val, val['a'] и val['a']['b'] являются объектами. Если val['a'] или val['a']['b'] не определены, они будут созданы как пустые объекты и заполнены по мере необходимости. Однако, если сам val или одно из промежуточных значений определено как не объект, такой как строка, число или jsonb null, процесс обхода не может продолжаться, поэтому возникает ошибка и транзакция прерывается.

Пример синтаксиса индексации:


-- Extract object value by key
SELECT ('{"a": 1}'::jsonb)['a'];

-- Extract nested object value by key path
SELECT ('{"a": {"b": {"c": 1}}}'::jsonb)['a']['b']['c'];

-- Extract array element by index
SELECT ('[1, "2", null]'::jsonb)[1];

-- Update object value by key. Note the quotes around '1': the assigned
-- value must be of the jsonb type as well
UPDATE table_name SET jsonb_field['key'] = '1';

-- This will raise an error if any record's jsonb_field['a']['b'] is something
-- other than an object. For example, the value {"a": 1} has a numeric value
-- of the key 'a'.
UPDATE table_name SET jsonb_field['a']['b']['c'] = '1';

-- Filter records using a WHERE clause with subscripting. Since the result of
-- subscripting is jsonb, the value we compare it against must also be jsonb.
-- The double quotes make "value" also a valid jsonb string.
SELECT * FROM table_name WHERE jsonb_field['key'] = '"value"';

jsonb Присваивание через индексирование обрабатывает несколько крайних случаев по-разному по сравнению с jsonb_set. Когда исходное значение jsonb равно NULL, присваивание через индексирование будет выполняться так, как если бы это было пустое значение JSON типа (объект или массив), подразумеваемого ключом индексирования:

-- Where jsonb_field was NULL, it is now {"a": 1}
UPDATE table_name SET jsonb_field['a'] = '1';

-- Where jsonb_field was NULL, it is now [1]
UPDATE table_name SET jsonb_field[0] = '1';

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

-- Where jsonb_field was [], it is now [null, null, 2];
-- where jsonb_field was [0], it is now [0, null, 2]
UPDATE table_name SET jsonb_field[2] = '2';

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

-- Where jsonb_field was {}, it is now {"a": [{"b": 1}]}
UPDATE table_name SET jsonb_field['a'][0]['b'] = '1';

-- Where jsonb_field was [], it is now [null, {"a": 1}]
UPDATE table_name SET jsonb_field[1]['a'] = '1';

8.14.6. Преобразования

Дополнительные расширения доступны, которые реализуют преобразования для типа jsonb для различных процедурных языков.

Расширения для PL/Perl называются jsonb_plperl и jsonb_plperlu. Если вы их используете, значения jsonb будут отображаться на соответствующие массивы, хеши и скаляры Perl.

Расширение для PL/Python называется jsonb_plpython3u. Если вы его используете, значения jsonb отображаются на словари, списки и скаляры Python, в зависимости от контекста.

Из этих расширений, jsonb_plperl считается доверенным, то есть его можно установить несуперпользователям, у которых есть привилегия CREATE в текущей базе данных. Для установки остальных требуется привилегия суперпользователя.

8.14.7. jsonpath Тип

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

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

  • Точка (.) используется для доступа к членам.

  • Квадратные скобки ([]) используются для доступа к массиву.

  • Массивы SQL/JSON начинаются с 0, в отличие от обычных массивов SQL, которые начинаются с 1.

Выражение SQL/JSON-пути обычно записывается в SQL-запросе в виде SQL-строкового литерала, поэтому оно должно быть заключено в апострофы, и любые апострофы, необходимые внутри значения, должны быть удвоены (см. Раздел 4.1.2.1). Некоторые формы выражений пути требуют строковых литералов внутри них. Эти встроенные строковые литералы следуют соглашениям JavaScript/ECMAScript: они должны быть окружены двойными кавычками, и обратные косые черты могут быть использованы внутри них для представления символов, которые иначе сложно ввести. В частности, способ записи двойной кавычки внутри встроенного строкового литерала - это \", а для записи самого обратного слеша необходимо написать \\. Другие специальные последовательности обратного слеша включают те, которые распознаются в строках JSON: \b, \f, \n, \r, \t, \v для различных управляющих символов ASCII, и \uNNNN для символа Unicode, идентифицируемого его 4-значным кодовым значением в шестнадцатеричной системе. Синтаксис обратного слеша также включает два случая, не разрешенных в JSON: \xNN для кода символа, записанного только двумя шестнадцатеричными цифрами, и \u{N...} для кода символа, записанного от 1 до 6 шестнадцатеричных цифр.

Выражение пути состоит из последовательности элементов пути, которые могут быть любыми из следующих:

  • Путь литералов JSON примитивных типов: Юникод текст, числовой, true, false или null.

  • Все переменные пути перечислены в Таблица 8.24.

  • Все операторы доступа перечислены в Таблица 8.25.

  • jsonpath перечислены операторы и методы, указанные в Раздел 9.16.2.2.

  • Круглые скобки, которые могут использоваться для задания выражений фильтрации или определения порядка вычисления пути.

Для получения подробной информации о использовании выражений jsonpath с функциями запросов SQL/JSON см. Раздел 9.16.2.

Таблица 8.24. jsonpath Переменные

ПеременнаяОписание
$Переменная, представляющая значение JSON, которое запрашивается (элемент контекста).
$varname A named variable. Its value can be set by the parameter vars of several JSON processing functions; see Таблица 9.48 for details.
@Переменная, представляющая результат вычисления пути в выражениях фильтрации.

Таблица 8.25. Аксессоры jsonpath

Оператор доступаОписание

.key

."$varname"

Член-аксессор, который возвращает член объекта с указанным ключом. Если имя ключа совпадает с именем переменной, начинающейся с символа $ или не соответствует правилам JavaScript для идентификатора, оно должно быть заключено в двойные кавычки, чтобы сделать его строковым литералом.

.*

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

.**

Рекурсивный доступ к члену с использованием маски, который обрабатывает все уровни иерархии JSON текущего объекта и возвращает все значения членов, независимо от их уровня вложенности. Это расширение Tantor SE стандарта SQL/JSON.

.**{level}

.**{start_level до end_level}

Как .**, но выбирает только указанные уровни иерархии JSON. Уровни вложенности указываются в виде целых чисел. Уровень ноль соответствует текущему объекту. Чтобы получить доступ к самому нижнему уровню вложенности, можно использовать ключевое слово last. Это расширение Tantor SE стандарта SQL/JSON.

[subscript, ...]

Доступ к элементу массива. subscript может быть задан в двух формах: index или start_index to end_index. Первая форма возвращает один элемент массива по его индексу. Вторая форма возвращает срез массива по диапазону индексов, включая элементы, соответствующие заданным start_index и end_index.

Указанный index может быть целым числом, а также выражением, возвращающим одно числовое значение, которое автоматически приводится к целому числу. Индекс ноль соответствует первому элементу массива. Вы также можете использовать ключевое слово last для обозначения последнего элемента массива, что полезно для работы с массивами неизвестной длины.

[*]

Метод чтения элементов массива-специальных символов, который возвращает значения всех элементов массива.




[7] Для этой цели термин значение включает элементы массива, хотя в терминологии JSON иногда элементы массива рассматриваются как отдельные от значений внутри объектов.