JSON-пути | Tarantool
Документация на русском языке
поддерживается сообществом

JSON-пути

Since version 2.3, Tarantool supports JSON path updates. You can update or upsert formatted tuple / space / index fields by name (not only by field number). Updates of nested structures are also supported.

Пример:

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 хоп.
Нашли ответ на свой вопрос?
Обратная связь