Tarantool CE/EE Documentation portal logo
Помощь
Обновлена 15 сентября 2026 г. в 08:55

JSON-пути

Общие сведения

Начиная с версии 2.3, в Tarantool поддерживается обновление по JSON-путям. Обновлять и выполнять upsert полей форматированных кортежей / пространств / индексов можно по имени (а не только по номеру поля). Также поддерживается обновление вложенных структур.

Пример:

tarantool> box.cfg{};         > format = {};         > format[1] = {'field1', 'unsigned'};         > format[2] = {'field2', 'map'};         > format[3] = {'field3', 'array'};         > format[4] = {'field4', 'string', is_nullable = true}---...tarantool> s = box.schema.create_space('test', {format = format});         > _ = s:create_index('pk')---...tarantool> t = {         >     1,         >     {         >         key1 = 'value',         >         key2 = 10         >     },         >     {         >         2,         >         3,         >         {key3 = 20}         >     }         > }---...tarantool> t = s:replace(t)---...tarantool> t:update({{'=', 'field2.key1', 'new_value'}})---- [1, {'key1': 'new_value', 'key2': 10}, [2, 3, {'key3': 20}]]...tarantool> t:update({{'+', 'field3[2]', 1}})---- [1, {'key1': 'value', 'key2': 10}, [2, 4, {'key3': 20}]]...tarantool> s:update({1}, {{'!', 'field4', 'inserted value'}})---- [1, {'key1': 'value', 'key2': 10}, [2, 3, {'key3': 20}], 'inserted value']...tarantool> s:update({1}, {{'#', '[2].key2', 1}, {'=', '[3][3].key4', 'value4'}})---- [1, {'key1': 'value'}, [2, 3, {'key3': 20, 'key4': 'value4'}], 'inserted value']...tarantool> s:upsert({1, {k = 'v'}, {}}, {{'#', '[2].key1', 1}})---...tarantool> s:select{}---- - [1, {}, [2, 3, {'key3': 20, 'key4': 'value4'}], 'inserted value']...

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

Например, для имени поля field.name.like.json это обновление

{object-name}:update({..., 'field.name.like.json', ...})

обновит именно это поле целиком, а не ключи field -> name -> like -> json. Если это имя нужно вам как часть большего пути, то его нужно обернуть в кавычки "" или квадратные скобки []:

{object-name}:update({..., '["field.name.like.json"].next.fields', ...})

Есть несколько правил для обновления через JSON:

  • Операция '!' не может использоваться для создания всех промежуточных узлов пути. Например, {'!', 'field1[1].field3', ...} не может создать поля 'field1' и '[1]' — они должны существовать.

  • Операция '#' при применении к ассоциативным массивам не может удалить более одного ключа за раз. То есть её аргумент всегда должен быть равен 1 для ассоциативных массивов. {'#', 'field1.field2', 1} – разрешено;

    {'#', 'field1.field2', 10} – не разрешено.

    Это ограничение возникает из-за проблемы, что ключи на ассоциативном массиве все равно не упорядочены, а '#' с более чем 1 ключом приведет к неопределенному поведению.

  • Операция '!' для ассоциативных массивов не может создать ключ, если он уже существует.

  • Если ассоциативный массив содержит нестроковые ключи (логические значения, числа, ассоциативные массивы, массивы — что угодно), то такие ключи нельзя обновить через JSON-пути. Однако обновлять строковые ключи в таком массиве по-прежнему разрешено.

Почему обновления с помощью JSON-путей хороши, и их следует предпочитать, когда нужно обновить только часть кортежа:

  • Они занимают меньше места в WAL, так как при обновлении сохраняются только ключи, операции и аргументы. Хранить обновление одного глубоко вложенного поля выгоднее, чем всего кортежа.
  • Они работают быстрее. Во-первых, потому что реализованы на C и не имеют проблем с Lua GC и динамической типизацией. Во-вторых, некоторые случаи работы с JSON-путями сильно оптимизированы. Например, обновление по одному JSON-пути требует O(1) памяти независимо от глубины пути (не считая аргументов обновления).
  • Они доступны удалённым клиентам, как и любые другие DML-операции. До появления обновлений по JSON-путям в Tarantool для обновления глубоко вложенной части кортежа было необходимо получить кортеж, обновить его в памяти и отправить обратно — 2 сетевых перехода. С JSON-путями это может быть 1 переход, если обновление можно описать в виде пути.