Функции и операторы JSON
В этом разделе описываются:
-
функции и операторы для обработки и создания данных JSON
-
язык путей SQL/JSON
Чтобы узнать больше о стандарте SQL/JSON, обратитесь к стандарту ISO/IEC TR 19075-6. Подробную информацию о типах JSON, поддерживаемых в QHB, см. в разделе Типы JSON.
Обработка и создание данных JSON
В Таблице 44 приведены имеющиеся операторы для использования с типами данных JSON (см. раздел Типы JSON). Кроме того, для типа jsonb (но не для json) имеются обычные операторы сравнения, приведенные в таблице Операторы сравнения. Эти операторы сравнения следуют правилам упорядочивания для операций B-дерева, изложенным в подразделе Индексация jsonb.
Таблица 44. Операторы для типов json и jsonb
Оператор |
||
---|---|---|
Описание Пример(ы) |
||
json -> integer → json jsonb -> integer → jsonb |
||
Извлекает n-й элемент массива JSON (элементы массива индексируются с нуля, но отрицательные числа считаются с конца).'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> 2 → {"c":"baz"} '[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> -3 → {"a":"foo"} |
||
json -> text → json jsonb -> text → jsonb |
||
Извлекает поле объекта JSON по заданному ключу.'{"a": {"b":"foo"}}'::json -> 'a' → {"b":"foo"} |
||
json ->> integer → text jsonb ->> integer → text |
||
Извлекает n-й элемент массива JSON в виде значения типа text.'[1,2,3]'::json ->> 2 → 3 |
||
json ->> text → text jsonb ->> text → text |
||
Извлекает поле объекта JSON по заданному ключу в виде значения типа text.'{"a":1,"b":2}'::json ->> 'b' → 2 |
||
json #> text[] → json jsonb #> text[] → jsonb |
||
Извлекает дочерний объект JSON по заданному пути, где элементами пути могут быть ключи полей или индексы массивов.'{"a": {"b": ["foo","bar"]}}'::json #> '{a,b,1}' → "bar" |
||
json #>> text[] → text jsonb #>> text[] → text |
||
Извлекает дочерний объект JSON по заданному пути в виде значения типа text.'{"a": {"b": ["foo","bar"]}}'::json #>> '{a,b,1}' → bar |
Примечание
Если структура входных данных JSON не соответствует запросу, например, если заданного ключа или элемента массива не существует, операторы извлечения поля/элемента/пути не выдают ошибку, а возвращают NULL.
Некоторые из следующих операторов существуют только для jsonb, как показано в Таблице 45. В подразделе Индексация jsonb описывается, как эти операторы можно использовать для эффективного поиска индексированных данных jsonb.
Таблица 45. Дополнительные операторы jsonb
Оператор |
||
---|---|---|
Описание Пример(ы) |
||
jsonb @> jsonb → boolean | ||
В первое значение JSON вложено второе? (Подробную информацию о вложении см. в подразделе Проверка на вложение и существование в jsonb.)'{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb → t |
||
jsonb <@ jsonb → boolean | ||
Первое значение JSON вложено во второе?'{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb → t |
||
jsonb ? text → boolean | ||
Текстовая строка существует в значении JSON в качестве ключа верхнего уровня или элемента массива?'{"a":1, "b":2}'::jsonb ? 'b' → t |
||
jsonb ?| text[] → boolean | ||
Какие-либо строки в текстовом массиве существуют в качестве ключей верхнего уровня или элементов массива?'{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'd'] → t |
||
jsonb ?& text[] → boolean | ||
Все строки в текстовом массиве существуют в качестве ключей верхнего уровня или элементов массива?'["a", "b", "c"]'::jsonb ?& array['a', 'b'] → t |
||
jsonb || jsonb → jsonb | ||
Конкатенирует два значения jsonb. Конкатенация двух массивов генерирует массив, содержащий все элементы каждого аргумента. Конкатенация двух объектов генерирует объект, содержащий объединение их ключей, при этом при наличии дубликатов ключей выбирается значение из второго объекта. Все другие случаи обрабатываются путем преобразования аргументов, отличных от массивов, в массивы с одним элементом, а затем конкатенируя их как два массива. Не работает рекурсивно: объединяются только массивы или структуры объекта на верхнем уровне.'["a", "b"]'::jsonb || '["a", "d"]'::jsonb → ["a", "b", "a", "d"] '{"a": "b"}'::jsonb || '{"c": "d"}'::jsonb → {"a": "b", "c": "d"} '[1, 2]'::jsonb || '3'::jsonb → [1, 2, 3] '{"a": "b"}'::jsonb || '42'::jsonb → [{"a": "b"}, 42] Чтобы вставить один массив в другой за одну запись, оберните его в дополнительный слой массива, например: '[1, 2]'::jsonb || jsonb_build_array('[3, 4]'::jsonb) → [1, 2, [3, 4]] |
||
jsonb - text → jsonb | ||
Удаляет ключ (и его значение) из объекта JSON или соответствующие строковые значения из массива JSON.'{"a": "b", "c": "d"}'::jsonb - 'a' → {"c": "d"} '["a", "b", "c", "b"]'::jsonb - 'b' → ["a", "c"] |
||
jsonb - text[] → jsonb | ||
Удаляет все соответствующие ключи или элементы массива из левого операнда.'{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[] → {} |
||
jsonb - integer → jsonb | ||
Удаляет элемент массива с заданным индексом (отрицательные числа считаются с конца). Выдает ошибку, если значение JSON — не массив.'["a", "b"]'::jsonb - 1 → ["a"] |
||
jsonb #- text[] → jsonb | ||
Удаляет поле или элемент массива по заданному пути, где элементы пути могут быть ключами полей или индексами массивов.'["a", {"b":1}]'::jsonb #- '{1,b}' → ["a", {}] |
||
jsonb @? jsonpath → boolean | ||
Возвращает ли путь JSON какой-либо элемент для заданного значения JSON?'{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)' → t |
||
jsonb @@ jsonpath → boolean | ||
Возвращает результат проверки предиката пути JSON для заданного значения JSON. Учитывается только первый элемент результата. Если результат не является логическим, возвращается NULL.'{"a":[1,2,3,4,5]}'::jsonb @@ '$.a[*] > 2' → t |
Примечание
Операторы jsonpath@?
и@@
подавляют следующие ошибки: отсутствие поля объекта или элемента массива, неожиданный тип элемента JSON и ошибки в числах и дате/времени. Это может быть полезно при поиске в коллекциях документов JSON с различной структурой.
В Таблице 46 приведены имеющиеся функции для создания значений json и jsonb.
Таблица 46. Функции для создания JSON
Функция |
||
---|---|---|
Описание Пример(ы) |
||
to_json ( anyelement ) → json to_jsonb ( anyelement ) → jsonb |
||
Преобразует любое значение SQL в json или jsonb. Массивы и составные объекты преобразуются рекурсивно в массивы и объекты (многомерные массивы становятся в JSON массивами массивов). В иных случаях, если задано приведение типа данных SQL к json, то для выполнения этого преобразования используется эта функция приведения;[b] для всех остальных выдается скалярное значение JSON. Значения всех скалярных типов, кроме числового, логического и NULL, будут представлены в виде текста, в который при необходимости будет добавлено экранирование символов для получения допустимого строкового значения JSON.to_json('Fred said "Hi."'::text) → "Fred said \"Hi.\"" to_jsonb(row(42, 'Fred said "Hi."'::text)) → {"f1": 42, "f2": "Fred said \"Hi.\""} |
||
array_to_json ( anyarray [, boolean ] ) → json | ||
Преобразует массив SQL в массив JSON. Поведение аналогично функции to_json, за исключением того, что если необязательный логический параметр равен true, между элементами массива верхнего уровня добавятся переводы строк.array_to_json('{{1,5},{99,100}}'::int[]) → [[1,5],[99,100]] |
||
row_to_json ( record [, boolean ] ) → json | ||
Преобразует составное значение SQL в объект JSON. Поведение аналогично функции to_json, за исключением того, что если необязательный логический параметр равен true, между элементами верхнего уровня добавятся переводы строк.row_to_json(row(1,'foo')) → {"f1":1,"f2":"foo"} |
||
json_build_array ( VARIADIC "any" ) → json jsonb_build_array ( VARIADIC "any" ) → jsonb |
||
Формирует массив JSON (возможно, неоднородный по типам) из переменного списка аргументов. Каждый аргумент преобразуется методом to_json или to_jsonb.json_build_array(1, 2, 'foo', 4, 5) → [1, 2, "foo", 4, 5] |
||
json_build_object ( VARIADIC "any" ) → json jsonb_build_object ( VARIADIC "any" ) → jsonb |
||
Формирует объект JSON из переменного списка аргументов. По соглашению, в списке аргументов по очереди перечисляются ключи и значения. Аргументы-ключи приводятся к текстовому типу; аргументы-значения преобразуются методом to_json или to_jsonb.json_build_object('foo', 1, 2, row(3,'bar')) → {"foo" : 1, "2" : {"f1":3,"f2":"bar"}} |
||
json_object ( text[] ) → json jsonb_object ( text[] ) → jsonb |
||
Формирует объект JSON из текстового массива. Этот массив должен иметь либо ровно одну размерность с четным числом членов (в этом случае они воспринимаются как чередующиеся пары ключ/значение), либо две размерности, и при этом каждый внутренний массив содержит ровно два элемента, которые воспринимаются как пара ключ/значение. Все значения преобразуются в строки JSON.json_object('{a, 1, b, "def", c, 3.5}') → {"a" : "1", "b" : "def", "c" : "3.5"} json_object('{{a, 1}, {b, "def"}, {c, 3.5}}') → {"a" : "1", "b" : "def", "c" : "3.5"} |
||
json_object ( ключи text[], значения text[] ) → json jsonb_object ( ключи text[], значения text[] ) → jsonb |
||
Эта форма json_object принимает ключи и значения по парам из отдельных текстовых массивов. В остальном она идентична форме с одним аргументом.json_object('{a,b}', '{1,2}') → {"a": "1", "b": "2"} |
||
[b] Например, в расширении hstore определено приведение типа hstore к json, поэтому значения hstore, преобразованные посредством функций создания JSON, будут представлены в виде объектов JSON, а не примитивных строковых значений. |
В Таблице 47 показаны имеющиеся функции для обработки значений json и jsonb.
Таблица 47. Функции для обработки JSON
Функция |
||
---|---|---|
Описание Пример(ы) |
||
json_array_elements ( json ) → setof json jsonb_array_elements ( jsonb ) → setof jsonb |
||
Разворачивает массив JSON верхнего уровня в набор значений JSON.
|
||
json_array_elements_text ( json ) → setof text jsonb_array_elements_text ( jsonb ) → setof text |
||
Разворачивает массив JSON верхнего уровня в набор значений text.
|
||
json_array_length ( json ) → integer jsonb_array_length ( jsonb ) → integer |
||
Возвращает количество элементов в массиве JSON верхнего уровня.json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]') → 5 |
||
json_each ( json ) → setof record ( ключ text, значение json ) jsonb_each ( jsonb ) → setof record ( ключ text, значение jsonb ) |
||
Разворачивает объект JSON верхнего уровня в набор пар ключ/значение.
|
||
json_each_text ( json ) → setof record ( ключ text, значение text ) jsonb_each_text ( jsonb ) → setof record ( ключ text, значение text ) |
||
Разворачивает объект JSON верхнего уровня в набор пар ключ/значение. Возвращаемые значения будут иметь тип text.
|
||
json_extract_path ( целевой_json json, VARIADIC элементы_пути text[] ) → json jsonb_extract_path ( целевой_json jsonb, VARIADIC элементы_пути text[] ) → jsonb |
||
Извлекает подобъект JSON по заданному пути. (Функционально это равнозначно действию оператора #> , но в некоторых случаях может быть удобнее записать путь в виде списка с переменным числом аргументов.)json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6') → "foo" |
||
json_extract_path_text ( целевой_json json, VARIADIC элементы_пути text[] ) → text jsonb_extract_path_text ( целевой_json jsonb, VARIADIC элементы_пути text[] ) → text |
||
Извлекает подобъект JSON по заданному пути в виде значения text. (Функционально это равнозначно действию оператора #>> .)json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6') → foo |
||
json_object_keys ( json ) → setof text jsonb_object_keys ( jsonb ) → setof text |
||
Возвращает набор ключей в объекте JSON верхнего уровня.
|
||
json_populate_record ( основа anyelement, целевой_json json ) → anyelement jsonb_populate_record ( основа anyelement, целевой_json jsonb ) → anyelement |
||
Разворачивает объект JSON верхнего уровня в строку, имеющую составной тип аргумента основа. Объект JSON сканируется на наличие полей, чьи имена соответствуют именам столбцов типа выходной строки, и их значения вставляются в эти столбцы вывода. (Поля, не соответствующие именам никаких выходных столбцов, игнорируются.) Как правило, значение основы просто равно NULL, что означает, что выходные столбцы не соответствующие полям объекта, будут заполнены значениями NULL. Однако если основа отлична от NULL, то для заполнения таких столбцов будут использованы содержащиеся в нем значения.
Для преобразования значения JSON в SQL-тип выходного столбца последовательно применяются следующие правила:
|
||
json_populate_recordset ( основа anyelement, целевой_json json ) → setof anyelement jsonb_populate_recordset ( основа anyelement, целевой_json jsonb ) → setof anyelement |
||
Разворачивает массив JSON верхнего уровня с объектами в набор строк, имеющих составной тип аргумента основа. Каждый элемент массива JSON обрабатывается так же, как описано выше для json[b]_populate_record.
|
||
json_to_record ( json ) → record jsonb_to_record ( jsonb ) → record |
||
Разворачивает объект JSON верхнего уровня в строку, имеющую составной тип, определенный в предложении AS. (Как и со всеми функциями, возвращающими значение record, вызывающий запрос должен явно определить структуру записи в предложении AS.) Выходная запись заполняется значениями полей объекта JSON так же, как описано выше для json[b]_populate_record. Поскольку этой функции не передается значение записи, несоответствующие столбцы всегда заполняются значениями NULL.
|
||
json_to_recordset ( json ) → setof record jsonb_to_recordset ( jsonb ) → setof record |
||
Разворачивает массив JSON верхнего уровня с объектами в набор строк, имеющих составной тип, определенный в предложении AS. (Как и со всеми функциями, возвращающими значение record, вызывающий запрос должен явно определить структуру записи в предложении AS.) Каждый элемент массива JSON обрабатывается так же, как описано выше для json[b]_populate_record.
|
||
jsonb_set ( цель jsonb, путь text[], новое_значение jsonb [, создать_если_отсутствует boolean ] ) → jsonb | ||
Возвращает цель, где элемент по указанному пути заменяется новым_значением, либо новое_значение добавляется, если аргумент создать_если_отсутствует равен true (это значение по умолчанию) и элемент, на который указывает путь, не существует. Все предыдущие звенья пути должны существовать, иначе цель будет возвращена без изменений. Как и с операторами, ориентированными на пути, отрицательные целые числа, находящиеся в пути, считают элементы с конца массивов JSON. Если последнее звено пути является индексом, выходящим за границы массива, и аргумент создать_если_отсутствует равен true, новое значение добавляется в начало массива, когда индекс отрицательный, или в его конец, когда индекс положительный.jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', '[2,3,4]', false) → [{"f1": [2, 3, 4], "f2": null}, 2, null, 3] jsonb_set('[{"f1":1,"f2":null},2]', '{0,f3}', '[2,3,4]') → [{"f1": 1, "f2": null, "f3": [2, 3, 4]}, 2] |
||
jsonb_set_lax ( цель jsonb, путь text[], новое_значение jsonb [, создать_если_отсутствует boolean [, обращение_с_null text ]] ) → jsonb | ||
Если новое_значение отлично от NULL, эта функция ведет себя идентично jsonb_set. В противном случае она действует согласно аргументу обращение_с_null, который может принимать значения 'raise_exception' (сгенерировать исключение), 'use_json_null' (использовать NULL в JSON), 'delete_key' (удалить ключ) или 'return_target' (вернуть цель без изменений). Значение по умолчанию — 'use_json_null'.jsonb_set_lax('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', null) → [{"f1":null,"f2":null},2,null,3] jsonb_set_lax('[{"f1":99,"f2":null},2]', '{0,f3}', null, true, 'return_target') → [{"f1": 99, "f2": null}, 2] |
||
jsonb_insert ( цель jsonb, путь text[], новое_значение jsonb [, вставить_после boolean ] ) → jsonb | ||
Возвращает цель с вставленным в нее новым_значением. Если элемент, на который указывает путь, является элементом массива, новое_значение будет вставлено перед этим элементом, если параметр вставить_после равен false (это значение по умолчанию), или после него, если вставить_после равен true. Если элемент, на который указывает путь, является полем объекта, новое_значение будет вставлено, только если объект еще не содержит этот ключ. Все предыдущие звенья пути должны существовать, иначе цель будет возвращена без изменений. Как и с операторами, ориентированными на пути, отрицательные целые числа, находящиеся в пути, считают элементы с конца массивов JSON. Если последнее звено пути является индексом, выходящим за границы массива, новое значение добавляется в начало массива, когда индекс отрицательный, или в его конец, когда тот положительный.jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"') → {"a": [0, "new_value", 1, 2]} jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"', true) → {"a": [0, 1, "new_value", 2]} |
||
json_strip_nulls ( json ) → json jsonb_strip_nulls ( jsonb ) → jsonb |
||
Рекурсивно удаляет из заданного значения JSON все поля объектов, имеющие значения NULL. Значения NULL, не относящиеся к полям объектов, не затрагиваются.json_strip_nulls('[{"f1":1, "f2":null}, 2, null, 3]') → [{"f1":1},2,null,3] |
||
jsonb_path_exists ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → boolean | ||
Проверяет, возвращает ли путь JSON какой-либо элемент для заданного значения JSON. Если задается аргумент переменные, он должен быть объектом JSON, и его поля предоставляют именованные значения, подставляемые в выражение jsonpath. Если задается аргумент немой_режим и он равен true, эта функция подавляет те же ошибки, что и операторы @? и @@ .jsonb_path_exists('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') → t |
||
jsonb_path_match ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → boolean | ||
Возвращает результат проверки предиката пути JSON для заданного значения JSON. Учитывается только первый элемент результата. Если результат не является логическим, возвращается NULL. Необязательные аргументы переменные и немой_режим действуют так же, как и для jsonb_path_exists.jsonb_path_match('{"a":[1,2,3,4,5]}', 'exists($.a[*] ? (@ >= $min && @ <= $max))', '{"min":2,
"max":4}') → t |
||
jsonb_path_query ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → setof jsonb | ||
Возвращает все элементы JSON, полученные по данному пути JSON для заданного значения JSON. Необязательные аргументы переменные и немой_режим действуют так же, как и для jsonb_path_exists.
|
||
jsonb_path_query_array ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → jsonb | ||
Возвращает все элементы JSON, полученные по данному пути JSON для заданного значения JSON, в виде массива JSON. Необязательные аргументы переменные и немой_режим действуют так же, как и для jsonb_path_exists.jsonb_path_query_array('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') → [2, 3, 4] |
||
jsonb_path_query_first ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → jsonb | ||
Возвращает первый элемент JSON, полученный по данному пути JSON для заданного значения JSON. Если результатов нет, возвращает NULL. Необязательные аргументы переменные и немой_режим действуют так же, как и для jsonb_path_exists.jsonb_path_query_first('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') → 2 |
||
jsonb_path_exists_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → boolean jsonb_path_match_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → boolean jsonb_path_query_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → setof jsonb jsonb_path_query_array_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → jsonb jsonb_path_query_first_tz ( цель jsonb, путь jsonpath [, переменные jsonb [, немой_режим boolean ]] ) → jsonb |
||
Данные функции действуют подобно их двойникам без суффикса _tz, за исключением того, что эти функции поддерживают сравнение значений даты/времени, которое требует преобразований с учетом часовых поясов. В следующем примере требуется интерпретация значения даты без указания времени 2015-08-02 в виде метки времени с часовым поясом, поэтому результат зависит от текущего значения параметра TimeZone. Из-за этой зависимости данные функции помечаются как стабильные, что означает, что их нельзя использовать в индексах. Их двойники являются постоянными, и поэтому могут применяться в индексах, но при запросе на подобные сравнения они будут выдавать ошибку.jsonb_path_exists_tz('["2015-08-01 12:00:00 -05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())') → t |
||
jsonb_pretty ( jsonb ) → text | ||
Преобразует заданное значение JSON в структурированный текст с отступами.
|
||
json_typeof ( json ) → text jsonb_typeof ( jsonb ) → text |
||
Возвращает тип значения JSON на верхнем уровне в виде текстовой строки. Возможные типы: object, array, string, number, boolean и null. (Не следует путать результат null со значением NULL в SQL; см. примеры.)json_typeof('-123.4') → number json_typeof('null'::json) → null json_typeof(NULL::json) IS NULL → t |
См. также раздел Агрегатные функции, где описывается агрегатная функция json_agg, агрегирующая значения записей в виде JSON, и агрегатная функция json_object_agg, агрегирующая пары значений в объект JSON, а также их аналоги для типа jsonb: jsonb_agg и jsonb_object_agg.
Язык путей SQL/JSON
Выражения пути SQL/JSON задают элементы, которые нужно извлечь из данных JSON аналогично выражениям XPath, используемым для доступа SQL к XML. В QHB выражения пути реализованы как тип данных jsonpath и могут использовать любые элементы, описанные в разделе Тип jsonpath.
Функции и операторы запросов 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, перечисленными в подразделе Операторы и методы пути SQL/JSON. Каждому имени метода должна предшествовать точка. Например, так можно получить размер массива:
$.track.segments.size()
Дополнительные примеры использования операторов и методов jsonpath в выражениях пути см. ниже в подразделе Операторы и методы пути SQL/JSON.
При определении пути также можно использовать одно или несколько выражений фильтра, которые работают аналогично предложению WHERE в SQL. Выражение фильтра начинается со знака вопроса и содержит условие в скобках:
? (условие)
Выражения фильтра должны быть указаны сразу после того этапа вычисления пути, к которому они должны применяться. Результат этого этапа фильтруется, чтобы содержать только те элементы, которые удовлетворяют предоставленному условию. В SQL/JSON определена трехзначная логику, поэтому условие может быть true, false или unknown. Значение unknown играет ту же роль, что и NULL в SQL, и его можно проверить с помощью предиката unknown. На дальнейших этапах вычисления пути задействуются только те элементы, для которых выражение фильтра вернуло true.
Функции и операторы, которые можно использовать в выражениях фильтра, перечислены в Таблице 49. Значение, подлежащее фильтрации (т. е. результат предыдущего этапа пути), обозначается в выражении фильтра переменной @. Для получения элементов этого компонента можно написать после @ операторы аксессоров.
Например, предположим, вы хотите получить все значения частоты сердцебиений, превышающие 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 в QHB имеет следующие отклонения от стандарта SQL/JSON:
-
Выражение пути может быть логическим предикатом, хотя стандарт SQL/JSON допускает предикаты только в фильтрах. Это необходимо для реализации оператора
@@
. Например, в QHB допустимо следующее выражение jsonpath:$.track.segments[*].HR < 70
-
Существуют небольшие различия в интерпретации шаблонов регулярных выражений, используемых в фильтрах like_regex; эти различия описаны в подразделе Регулярные выражения SQL/JSON.
Строгий и нестрогий режимы
При запросе данных JSON выражение пути может не соответствовать фактической структуре данных JSON. Попытка получить доступ к несуществующему члену объекта или элементу массива приводит к структурной ошибке. Для выражений пути SQL/JSON существует два режима обработки структурных ошибок:
-
lax (по умолчанию) — нестрогий режим, при котором механизм пути неявно адаптирует запрошенные данные к указанному пути. Все оставшиеся структурные ошибки подавляются и преобразуются в пустые последовательности SQL/JSON.
-
strict — строгий режим, в котором при возникновении структурной ошибки она выдается как есть.
Нестрогий режим облегчает сопоставление структуры документа JSON и выражения пути, если данные JSON не соответствуют ожидаемой схеме. Если операнд не соответствует требованиям конкретной операции, перед выполнением этой операции он может автоматически оборачиваться в массив SQL/JSON или разворачиваться путем преобразования его элементов в последовательность SQL/JSON. Кроме того, операторы сравнения автоматически разворачивают свои операнды в нестрогом режиме, поэтому массивы SQL/JSON можно сравнивать, не прикладывая дополнительных усилий. Массив размером 1 считается равным своему единственному элементу. Автоматическое разворачивание не выполняется только в тех случаях, когда:
-
Выражение пути содержит методы type() или size(), которые возвращают тип и количество элементов в массиве соответственно.
-
Запрашиваемые данные JSON содержат вложенные массивы. В этом случае разворачивается только самый внешний массив, а все внутренние массивы остаются неизменными. Таким образом, на каждом этапе вычисления пути неявное развертывание может опускаться только на один уровень.
Например, при запросе перечисленных выше данных GPS в нестрогом режиме можно абстрагироваться от того факта, что в них хранится массив сегментов:
lax $.track.segments.location
В строгом режиме указанный путь должен точно соответствовать структуре запрашиваемого документа JSON, чтобы вернуть элемент SQL/JSON, поэтому использование этого выражения пути приведет к ошибке. Чтобы получить тот же результат, что и в нестрогом режиме, следует явно развернуть массив segments:
strict $.track.segments\[\*\].location
В нестрогом режиме аксессор .**
может вызвать неожиданные результаты. Например,
следующий запрос выберет каждое значение HR дважды:
lax $.**.HR
Это происходит из-за того, что аксессор .**
выбирает и массив segments, и каждый
из его элементов, тогда как аксессор .HR
в нестрогом режиме автоматически
разворачивает массивы. Чтобы избежать неожиданных результатов, рекомендуется
использовать аксессор .**
только в строгом режиме. Следующий запрос выбирает
каждое значение HR только один раз:
strict $.**.HR
Операторы и методы пути SQL/JSON
В Таблице 48 показаны операторы и методы, имеющиеся в jsonpath. Обратите внимание, что унарные операторы и методы можно применять к нескольким значениям, полученным на предыдущем этапе пути, тогда как бинарные операторы (сложение и т. п.) можно применять только к отдельным значениям.
Таблица 48. Операторы и методы jsonpath
Оператор/Метод |
||
---|---|---|
Описание Пример(ы) |
||
число + число → число | ||
Сложениеjsonb_path_query('[2]', '$[0] + 3') → 5 |
||
+ число → число | ||
Унарный плюс (нет операции); в отличие от сложения, он может выполнить проход по нескольким значениямjsonb_path_query_array('{"x": [2,3,4]}', '+ $.x') → [2, 3, 4] |
||
число - число → число | ||
Вычитаниеjsonb_path_query('[2]', '7 - $[0]') → 5 |
||
- число → число | ||
Смена знака; в отличие от вычитания, он может выполнить проход по нескольким значениямjsonb_path_query_array('{"x": [2,3,4]}', '- $.x') → [-2, -3, -4] |
||
число * число → число | ||
Умножениеjsonb_path_query('[4]', '2 * $[0]') → 8 |
||
число / число → число | ||
Делениеjsonb_path_query('[8.5]', '$[0] / 2') → 4.2500000000000000 |
||
число % число → число | ||
Остаток целочисленного деления (по модулю)jsonb_path_query('[32]', '$[0] % 10') → 2 |
||
значение . type() → строка | ||
Тип элемента JSON (см. json_typeof)jsonb_path_query_array('[1, "2", {}]', '$[*].type()') → ["number", "string", "object"] |
||
значение . size() → число | ||
Размер элемента JSON (число элементов массива или 1, если это не массив)jsonb_path_query('{"m": [11, 15]}', '$.m.size()') → 2 |
||
значение . double() → число | ||
Приблизительное число с плавающей запятой, преобразованное из числа JSON или строкиjsonb_path_query('{"len": "1.9"}', '$.len.double() * 2') → 3.8 |
||
число . ceiling() → число | ||
Ближайшее целое число, большее или равное заданному числуjsonb_path_query('{"h": 1.3}', '$.h.ceiling()') → 2 |
||
число . floor() → число | ||
Ближайшее целое число, меньшее или равное заданному числуjsonb_path_query('{"h": 1.7}', '$.h.floor()') → 1 |
||
число . abs() → число | ||
Абсолютное значение (модуль) заданного числаjsonb_path_query('{"z": -0.3}', '$.z.abs()') → 0.3 |
||
строка . datetime() → тип_даты_времени (см. примечание) | ||
Значение даты/времени, преобразованное из строкиjsonb_path_query('["2015-8-1", "2015-08-12"]', '$[*] ? (@.datetime() < "2015-08-2".datetime())') → "2015-8-1" |
||
строка . datetime(шаблон) → тип_даты_времени (см. примечание) | ||
Значение даты/времени, преобразованное из строки с помощью заданного шаблона to_timestampjsonb_path_query_array('["12:30", "18:40"]', '$[*].datetime("HH24:MI")') → ["12:30:00", "18:40:00"] |
||
объект . keyvalue() → массив | ||
Пары ключ-значение объекта, представленные в виде массива объектов, содержащего три поля: "key" (ключ), "value" (значение) и "id"; "id" представляет собой уникальный идентификатор объекта, которому принадлежит данная пара ключ-значениеjsonb_path_query_array('{"x": "20", "y": 32}', '$.keyvalue()') → [{"id": 0, "key": "x", "value": "20"}, {"id": 0, "key": "y", "value": 32}] |
Примечание
Результирующим типом методов datetime() и datetime(шаблон) может быть date, timetz, time, timestamptz или timestamp. Оба метода определяют свой результирующий тип динамически.Метод datetime() последовательно пытается сопоставить свою входную строку с форматами ISO типов date, timetz, time, timestamptz и timestamp. На первом же подходящем формате он останавливается и выдает соответствующий тип данных.
Метод datetime(шаблон) определяет результирующий тип в соответствии с полями в предоставленной строке шаблона.
Методы datetime() и datetime(шаблон) применяют те же правила синтаксического анализа, что и функция SQL to_timestamp (см. раздел Функции для форматирования типов данных), но с тремя исключениями. Во-первых, эти методы не позволяют использовать в шаблоне коды без соответствия. Во-вторых, в строке шаблона допускаются только следующие разделители: знак минуса, точка, косая черта (слэш), запятая, апостроф, точка с запятой, двоеточие и пробел. В-третьих, разделители в строке шаблона должны в точности соответствовать входной строке.
Если нужно сравнить разные типы даты/времени, применяется неявное приведение. Значение date можно привести к типу timestamp или timestamptz, timestamp — к типу timestamptz, а time — к типу timetz. Однако все эти преобразования, кроме первого, зависят от текущего значения TimeZone и поэтому могут выполняться только в функциях jsonpath, учитывающих часовой пояс.
В Таблице 49 приведены имеющиеся элементы выражения фильтра.
Таблица 49. Элементы выражения фильтра jsonpath
Предикат/Значение |
||
---|---|---|
Описание Пример(ы) |
||
значение == значение → boolean | ||
Сравнение равенства (этот и другие операторы сравнения работают со всеми скалярными значениями JSON)jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == 1)') → [1, 1] jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == "a")') → ["a"] |
||
значение != значение → boolean значение <> значение → boolean |
||
Сравнение неравенстваjsonb_path_query_array('[1, 2, 1, 3]', '$[*] ? (@ != 1)') → [2, 3] jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <> "b")') → ["a", "c"] |
||
значение < значение → boolean | ||
Сравнение «меньше»jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ < 2)') → [1] |
||
значение <= значение → boolean | ||
Сравнение «меньше или равно»jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <= "b")') → ["a", "b"] |
||
значение > значение → boolean | ||
Сравнение «больше»jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ > 2)') → [3] |
||
значение >= значение → boolean | ||
Сравнение «больше или равно»jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ >= 2)') → [2, 3] |
||
true → boolean | ||
JSON-константа truejsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == true)') → {"name": "Chris", "parent": true} |
||
false → boolean | ||
JSON-константа falsejsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == false)') → {"name": "John", "parent": false} |
||
null → значение | ||
JSON-константа null (обратите внимание, что, в отличие от SQL, сравнение с null работает нормально)jsonb_path_query('[{"name": "Mary", "job": null}, {"name": "Michael", "job": "driver"}]', '$[*] ? (@.job == null) .name') → "Mary" |
||
логическое_значение && логическое_значение → boolean | ||
Логическое Иjsonb_path_query('[1, 3, 7]', '$[*] ? (@ > 1 && @ < 5)') → 3 |
||
логическое_значение || логическое_значение → boolean | ||
Логическое ИЛИjsonb_path_query('[1, 3, 7]', '$[*] ? (@ < 1 || @ > 5)') → 7 |
||
! логическое_значение → boolean | ||
Логическое НЕjsonb_path_query('[1, 3, 7]', '$[*] ? (!(@ < 5))') → 7 |
||
логическое_значение is unknown → boolean | ||
Проверяет, является ли unknown логическим условием.jsonb_path_query('[-1, 2, 7, "foo"]', '$[*] ? ((@ > 0) is unknown)') → "foo" |
||
строка like_regex строка [ flag строка ] → boolean | ||
Проверяет, соответствует ли первый операнд регулярному выражению, заданному во втором операнде, с необязательными модификациями, описываемыми строкой символов flag (см. подраздел Регулярные выражения SQL/JSON).jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c")') → ["abc", "abdacb"] jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c" flag "i")') → ["abc", "aBdC", "abdacb"] |
||
строка starts with строка → boolean | ||
Проверяет, является ли второй операнд начальной подстрокой первого.jsonb_path_query('["John Smith", "Mary Stone", "Bob Johnson"]', '$[*] ? (@ starts with "John")') → "John Smith" |
||
exists ( выражение_пути ) → boolean | ||
Проверяет, соответствует ли выражение пути хотя бы одному элементу SQL/JSON. Возвращает unknown, если это выражение пути могло вызвать ошибку; это используется во втором примере, чтобы избежать ошибки «ключ не найден» в строгом режиме.jsonb_path_query('{"x": [1, 2], "y": [2, 4]}', 'strict $.* ? (exists (@ ? (@[*] > 2)))') → [2, 4] jsonb_path_query_array('{"value": 41}', 'strict $ ? (exists (@.name)) .name') → [] |
Регулярные выражения SQL/JSON
Выражения путей SQL/JSON позволяют сопоставлять текст с регулярным выражением при помощи фильтра like_regex. Например, следующий запрос пути SQL/JSON будет соответствовать всем строкам в массиве, которые начинаются с английской гласной, без учета регистра:
$[*] ? (@ like_regex "^[aeiou]" flag "i")
Необязательная строка flag может включать один или несколько следующих символов:
i — сопоставления без учета регистра, m — допускается сопоставление ^
и
$
с переводами строк, s — допускается сопоставление .
с переводом строки,
и q — заключить в кавычки весь шаблон (сводя поиск к простому сопоставлению
подстроки).
Стандарт SQL/JSON заимствует свое определение для регулярных выражений из
оператора LIKE_REGEX
, в котором, в свою очередь, используется стандарт XQuery.
В настоящее время в QHB оператор LIKE_REGEX
не поддерживается.
Поэтому фильтр like_regex реализован с использованием механизма регулярных
выражений POSIX, описанного в подразделе Регулярные выражения POSIX. Это приводит
к различным незначительным несоответствиям стандартному поведению SQL/JSON,
которые каталогизированы в подразделе Отличия от XQuery (LIKE_REGEX). Тем не
менее, обратите внимание, что описанные там несовместимости флаговых букв не
применяются к SQL/JSON, поскольку в SQL/JSON флаговые буквы XQuery переводятся
во флаги, подходящие механизму POSIX.
Не забывайте, что аргумент шаблона like_regex является строковым литералом пути JSON, написанным в соответствии с правилами, приведенными в подразделе Тип jsonpath. В частности, это означает, что все обратные слеши в регулярном выражении необходимо дублировать. Например, чтобы сопоставить строковые значения корневого документа, содержащие только цифры, нужно написать следующее:
$.* ? (@ like_regex "^\\d+$")