Примеры CRUD-операций
В этом разделе приведены базовые сценарии использования и типичные ошибки для каждой операции с данными в Tarantool: INSERT, DELETE, UPDATE, UPSERT, REPLACE и SELECT. Перед выполнением примеров необходимо выполнить начальную загрузку экземпляра Tarantool, как показано ниже.
-- Create a space --bands = box.schema.space.create('bands')-- Specify field names and types --box.space.bands:format({{ name = 'id', type = 'unsigned' },{ name = 'band_name', type = 'string' },{ name = 'year', type = 'unsigned' }})-- Create a primary index --box.space.bands:create_index('primary', { parts = { 'id' } })-- Create a unique secondary index --box.space.bands:create_index('band', { parts = { 'band_name' } })-- Create a non-unique secondary index --box.space.bands:create_index('year', { parts = { { 'year' } }, unique = false })-- Create a multi-part index --box.space.bands:create_index('year_band', { parts = { { 'year' }, { 'band_name' } } })
Метод space_object.insert принимает корректно сформированный кортеж.
-- Insert a tuple with a unique primary key --tarantool> bands:insert{1, 'Scorpions', 1965}---- [1, 'Scorpions', 1965]...
insert также проверяет все ключи на дубликаты.
-- Try to insert a tuple with a duplicate primary key --tarantool> bands:insert{1, 'Scorpions', 1965}---- error: Duplicate key exists in unique index "primary" in space "bands" with oldtuple - [1, "Scorpions", 1965] and new tuple - [1, "Scorpions", 1965]...-- Try to insert a tuple with a duplicate secondary key --tarantool> bands:insert{2, 'Scorpions', 1965}---- error: Duplicate key exists in unique index "band" in space "bands" with old tuple- [1, "Scorpions", 1965] and new tuple - [2, "Scorpions", 1965]...-- Insert a second tuple with unique primary and secondary keys --tarantool> bands:insert{2, 'Pink Floyd', 1965}---- [2, 'Pink Floyd', 1965]...-- Delete all tuples --tarantool> bands:truncate()---...
Метод space_object.delete позволяет удалить кортеж по первичному ключу.
-- Insert test data --tarantool> bands:insert{1, 'Roxette', 1986}bands:insert{2, 'Scorpions', 1965}bands:insert{3, 'Ace of Base', 1987}bands:insert{4, 'The Beatles', 1960}-- Delete a tuple with an existing key --tarantool> bands:delete{4}---- [4, 'The Beatles', 1960]...tarantool> bands:select()---- - [1, 'Roxette', 1986]- [2, 'Scorpions', 1965]- [3, 'Ace of Base', 1987]...
Для удаления кортежа по указанному уникальному индексу также можно использовать index_object.delete.
-- Delete a tuple by the primary index --tarantool> bands.index.primary:delete{3}---- [3, 'Ace of Base', 1987]...tarantool> bands:select()---- - [1, 'Roxette', 1986]- [2, 'Scorpions', 1965]...-- Delete a tuple by a unique secondary index --tarantool> bands.index.band:delete{'Scorpions'}---- [2, 'Scorpions', 1965]...tarantool> bands:select()---- - [1, 'Roxette', 1986]...-- Try to delete a tuple by a non-unique secondary index --tarantool> bands.index.year:delete(1986)---- error: Get() doesn't support partial keys and non-unique indexes...tarantool> bands:select()---- - [1, 'Roxette', 1986]...-- Try to delete a tuple by a partial key --tarantool> bands.index.year_band:delete('Roxette')---- error: Invalid key part count in an exact match (expected 2, got 1)...-- Delete a tuple by a full key --tarantool> bands.index.year_band:delete{1986, 'Roxette'}---- [1, 'Roxette', 1986]...tarantool> bands:select()----...-- Delete all tuples --tarantool> bands:truncate()---...
Метод space_object.update позволяет обновить кортеж по
первичному ключу. Как и delete, метод update принимает полный ключ, а также операцию для выполнения.
-- Insert test data --tarantool> bands:insert{1, 'Roxette', 1986}bands:insert{2, 'Scorpions', 1965}bands:insert{3, 'Ace of Base', 1987}bands:insert{4, 'The Beatles', 1960}-- Update a tuple with an existing key --tarantool> bands:update({2}, {{'=', 2, 'Pink Floyd'}})---- [2, 'Pink Floyd', 1965]...tarantool> bands:select()---- - [1, 'Roxette', 1986]- [2, 'Pink Floyd', 1965]- [3, 'Ace of Base', 1987]- [4, 'The Beatles', 1960]...
Метод index_object.update обновляет кортеж по указанному уникальному индексу.
-- Update a tuple by the primary index --tarantool> bands.index.primary:update({2}, {{'=', 2, 'The Rolling Stones'}})---- [2, 'The Rolling Stones', 1965]...tarantool> bands:select()---- - [1, 'Roxette', 1986]- [2, 'The Rolling Stones', 1965]- [3, 'Ace of Base', 1987]- [4, 'The Beatles', 1960]...-- Update a tuple by a unique secondary index --tarantool> bands.index.band:update({'The Rolling Stones'}, {{'=', 2, 'The Doors'}})---- [2, 'The Doors', 1965]...tarantool> bands:select()---- - [1, 'Roxette', 1986]- [2, 'The Doors', 1965]- [3, 'Ace of Base', 1987]- [4, 'The Beatles', 1960]...-- Try to update a tuple by a non-unique secondary index --tarantool> bands.index.year:update({1965}, {{'=', 2, 'Scorpions'}})---- error: Get() doesn't support partial keys and non-unique indexes...tarantool> bands:select()---- - [1, 'Roxette', 1986]- [2, 'The Doors', 1965]- [3, 'Ace of Base', 1987]- [4, 'The Beatles', 1960]...-- Delete all tuples --tarantool> bands:truncate()---...
Метод space_object.upsert обновляет существующий кортеж или вставляет новый:
-
Если существующий кортеж найден по первичному ключу, Tarantool применяет к нему операцию обновления и игнорирует новый кортеж.
-
Если существующий кортеж не найден, Tarantool вставляет новый кортеж и игнорирует операцию обновления.
tarantool> bands:insert{1, 'Scorpions', 1965}---- [1, 'Scorpions', 1965]...-- As the first argument, upsert accepts a tuple, not a key --tarantool> bands:upsert({2}, {{'=', 2, 'Pink Floyd'}})---- error: Tuple field 2 (band_name) required by space format is missing...tarantool> bands:select()---- - [1, 'Scorpions', 1965]...tarantool> bands:delete(1)---- [1, 'Scorpions', 1965]...
Метод upsert действует как insert, если существующий кортеж не найден по
первичному ключу.
tarantool> bands:upsert({1, 'Scorpions', 1965}, {{'=', 2, 'The Doors'}})---...-- As you can see, {1, 'Scorpions', 1965} is inserted, ---- and the update operation is not applied. --tarantool> bands:select()---- - [1, 'Scorpions', 1965]...-- upsert with the same primary key but different values in other fields ---- applies the update operation and ignores the new tuple. --tarantool> bands:upsert({1, 'Scorpions', 1965}, {{'=', 2, 'The Doors'}})---...tarantool> bands:select()---- - [1, 'The Doors', 1965]...
Метод upsert выполняет поиск существующего кортежа по первичному индексу, а
не по вторичному. Это может привести к ошибке дублирования, если кортеж
нарушает уникальность вторичного индекса.
tarantool> bands:upsert({2, 'The Doors', 1965}, {{'=', 2, 'Pink Floyd'}})---- error: Duplicate key exists in unique index "band" in space "bands" with old tuple- [1, "The Doors", 1965] and new tuple - [2, "The Doors", 1965]...tarantool> bands:select()---- - [1, 'The Doors', 1965]...-- This works if uniqueness is preserved. --tarantool> bands:upsert({2, 'The Beatles', 1960}, {{'=', 2, 'Pink Floyd'}})---...tarantool> bands:select()---- - [1, 'The Doors', 1965]- [2, 'The Beatles', 1960]...-- Delete all tuples --tarantool> bands:truncate()---...
space_object.replace принимает корректно сформированный кортеж и выполняет поиск существующего кортежа по первичному ключу нового кортежа:
-
Если существующий кортеж найден, Tarantool удаляет его и вставляет новый кортеж.
-
Если существующий кортеж не найден, Tarantool вставляет новый кортеж.
tarantool> bands:replace{1, 'Scorpions', 1965}---- [1, 'Scorpions', 1965]...tarantool> bands:select()---- - [1, 'Scorpions', 1965]...tarantool> bands:replace{1, 'The Beatles', 1960}---- [1, 'The Beatles', 1960]...tarantool> bands:select()---- - [1, 'The Beatles', 1960]...tarantool> bands:truncate()---...
Метод replace может нарушить ограничения уникальности, как и upsert.
tarantool> bands:insert{1, 'Scorpions', 1965}- [1, 'Scorpions', 1965]...tarantool> bands:insert{2, 'The Beatles', 1960}---- [2, 'The Beatles', 1960]...tarantool> bands:replace{2, 'Scorpions', 1965}---- error: Duplicate key exists in unique index "band" in space "bands" with old tuple- [1, "Scorpions", 1965] and new tuple - [2, "Scorpions", 1965]...tarantool> bands:truncate()---...
Запрос space_object.select выполняет поиск кортежа
или набора кортежей в указанном спейсе по первичному ключу. Для поиска по указанному индексу
используйте index_object.select.
Эти методы работают с любыми ключами, включая уникальные и неуникальные, полные и частичные. Если
ключ частичный, select выполняет поиск по всем ключам, префикс которых
совпадает с указанной частью ключа.
tarantool> bands:insert{1, 'Roxette', 1986}bands:insert{2, 'Scorpions', 1965}bands:insert{3, 'The Doors', 1965}bands:insert{4, 'The Beatles', 1960}tarantool> bands:select(1)---- - [1, 'Roxette', 1986]...tarantool> bands:select()---- - [1, 'Roxette', 1986]- [2, 'Scorpions', 1965]- [3, 'The Doors', 1965]- [4, 'The Beatles', 1960]...tarantool> bands.index.primary:select(2)---- - [2, 'Scorpions', 1965]...tarantool> bands.index.band:select('The Doors')---- - [3, 'The Doors', 1965]...tarantool> bands.index.year:select(1965)---- - [2, 'Scorpions', 1965]- [3, 'The Doors', 1965]...
В этом примере показано, как просмотреть все спейсы и для каждого
вывести: приблизительное количество кортежей и первое поле первого
кортежа. Функция использует функции box.space из Tarantool — len()
и pairs(). Перебор спейсов реализован как сканирование системного
спейса _space, который содержит метаданные. Третье поле в _space
содержит имя спейса, поэтому ключевая инструкция space_name = v[3]
означает, что space_name — это поле space_name в кортеже _space,
только что полученном с помощью pairs(). Функция возвращает таблицу:
function example()local tuple_count, space_name, linelocal ta = {}for k, v in box.space._space:pairs() dospace_name = v[3]if box.space[space_name].index[0] ~= nil thentuple_count = '1 or more'elsetuple_count = '0'endline = space_name .. ' tuple_count =' .. tuple_countif tuple_count == '1 or more' thenfor k1, v1 in box.space[space_name]:pairs() doline = line .. '. first field in first tuple = ' .. v1[1]breakendendtable.insert(ta, line)endreturn taend
Ниже показан результат вызова этой функции:
tarantool> example()---- - _schema tuple_count =1 or more. first field in first tuple = cluster- _space tuple_count =1 or more. first field in first tuple = 272- _vspace tuple_count =1 or more. first field in first tuple = 272- _index tuple_count =1 or more. first field in first tuple = 272- _vindex tuple_count =1 or more. first field in first tuple = 272- _func tuple_count =1 or more. first field in first tuple = 1- _vfunc tuple_count =1 or more. first field in first tuple = 1- _user tuple_count =1 or more. first field in first tuple = 0- _vuser tuple_count =1 or more. first field in first tuple = 0- _priv tuple_count =1 or more. first field in first tuple = 1- _vpriv tuple_count =1 or more. first field in first tuple = 1- _cluster tuple_count =1 or more. first field in first tuple = 1...
В этом примере показано, как вывести имена и типы полей системного спейса — использование метаданных для поиска метаданных.
Для начала: как можно сделать выборку кортежа из _space, который
описывает _space?
Простой способ — посмотреть константы в box.schema, где видно, что
есть элемент с именем SPACE_ID == 288, поэтому следующие инструкции
возвращают нужный кортеж:
box.space._space:select{ 288 }-- или --box.space._space:select{ box.schema.SPACE_ID }
Другой способ — посмотреть кортежи в box.space._index, где видно,
что для спейса с номером 288 существует вторичный индекс с именем
'name', поэтому следующая инструкция также возвращает нужный кортеж:
box.space._space.index.name:select{ '_space' }
Однако непросто прочитать информацию из полученного кортежа:
tarantool> box.space._space.index.name:select{'_space'}---- - [280, 1, '_space', 'memtx', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'owner','type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'engine', 'type': 'str'},{'name': 'field_count', 'type': 'num'}, {'name': 'flags', 'type': 'str'}, {'name': 'format', 'type': '*'}]]...
Информация подается бессистемно, поскольку по формату поле №7 содержит
рекомендованные имена и типы данных. Как же получить эти данные?
Поскольку очевидно, что поле №7 представляет собой ассоциативный массив,
цикл for проведет организацию данных:
tarantool> do> local tuple_of_space = box.space._space.index.name:get{'_space'}> for _, field in ipairs(tuple_of_space[7]) do> print(field.name .. ', ' .. field.type)> end> endid, numowner, numname, strengine, strfield_count, numflags, strformat, *---...