How do I select a range of keys from tarantool, like with SELECT BETWEEN in SQL? - tarantool

Since this is on of the most common questions in https://t.me/tarantool and https://t.me/tarantoolru, I post the answer here.

space:pairs(from, 'GE'):
take_while(function(x) return x.field <= to end)
-- :totable() or use the result in the for-loop
For multipart keys see https://stackoverflow.com/a/57766656/1135874

You can do it using Lua as well as SQL.
1) Use a stored procedure in Lua, like this one:
function select_between(space_name, index_name, field_name, from, to)
local obj = index_name == nil and box.space[space_name] or box.space[space_name].index[index_name]
local result = {}
for _, tuple in obj:pairs(from, {iterator = 'GE'}) do
if (tuple[field_name] <= to) then
table.insert(result, tuple)
else
break
end
end
return result
end
select_between('test', nil, 'id', 1, 3)
2) Starting with Tarantool 2.0, you can use SQL (provided that you have space format):
box.execute('select * from "test" where "id" between 1 and 3;')

Related

How do I select several keys from tarantool at once, like with SELECT IN in SQL?

I want to select several records from Tarantool in one call, but don't see how can I pass several keys to space:get or space:select
You can do it using Lua as well as SQL.
1) Use a stored procedure in Lua, like this one:
function select_several(space_name, index_name, keys)
local obj = index_name == nil and box.space[space_name] or box.space[space_name].index[index_name]
local result = {}
for _, key in pairs(keys) do
table.insert(result, obj:get(key))
end
return result
end
...
select_several('test', nil, {1, 2})
2) Starting with Tarantool 2.0, you can use SQL (provided that you have space format):
box.execute('select * from "test" where "id" in (1, 3);')
One more variant equivalent to the SQL query select * from "test" where "id" in (1, 3) using LuaFun:
tarantool> box.space.test:pairs():filter(function (tuple) return tuple.id == 1 or tuple.id == 3 end):totable()
It is a generic variant if there is no 'id' index in the space, and it implies performing fullscan.
If a unique index named "id" exists, a more efficient variant is possible:
tarantool> fun.iter({1, 3}):map(function (value) return box.space.test.id:get(value) end):totable()
Otherwise if the index is not unique, then it will look like
tarantool> fun.iter({1, 3}):map(function (value) return box.space.test.id:select(value) end):reduce(function (result, data) for _, rec in ipairs(data) do table.insert(result, rec) end return result end, {})

GLua - Getting the difference between two tables

Disclaimer: This is Glua (Lua used by Garry's Mod)
I just need to compare tables between them and return the difference, like if I was substrating them.
TableOne = {thing = "bob", 89 = 1, 654654 = {"hi"}} --Around 3k items like that
TableTwo = {thing = "bob", 654654 = "hi"} --Same, around 3k
function table.GetDifference(t1, t2)
local diff = {}
for k, dat in pairs(t1) do --Loop through the biggest table
if(!table.HasValue(t2, t1[k])) then --Checking if t2 hasn't the value
table.insert(diff, t1[k]) --Insert the value in the difference table
print(t1[k])
end
end
return diff
end
if table.Count(t1) != table.Count(t2) then --Check if amount is equal, in my use I don't need to check if they are exact.
PrintTable(table.GetDifference(t1, t2)) --Print the difference.
end
My problem being that with only one of difference between the two tables, this returns me more than 200 items. The only item I added was a String. I tried many other functions like this one but they usually cause a stack overflow error because of the table's length.
Your problem is with this line
if(!table.HasValue(t2, t1[k])) then --Checking if t2 hasn't the value
Change it to this:
if(!table.HasValue(t2, k) or t1[k] != t2[k]) then --Checking if t2[k] matches
Right now what is happening is that you're looking at an entry like thing = "bob" and then you're looking to see whether t2 has "bob" as a key. And it doesn't. But neither did t1 so that shouldn't be regarded as a difference.

How i can perform request to tarantool like in mysql?

I need select from tarantool all datat by two values from one space.
How i can perform request to tarantool like in mysql?
select from aaa where a=1a22cadbdb or a=7f626e0123
Now i can make two requests:
box.space.logs:select({'1a22cadbdb'})
box.space.logs:select({'7f626e0123'})
but i don't know how to merge result into one ;(
Following code merge field[0] to lua table
a = box.space.logs:select({'1a22cadbdb'})
b = box.space.logs:select({'7f626e0123'})
c = { field_1 = a[0], field_2 = b[0] }
The select return tuple or tuples so you can extract value via [].
More details about select: http://tarantool.org/doc/book/box/box_index.html?highlight=select#lua-function.index_object.select
More details about tuple: http://tarantool.org/doc/book/box/box_tuple.html?highlight=tuple#lua-module.box.tuple
Nowadays Tarantool allows you to retrieve via SQL, for example box.execute([[select from "aaa" where "a"='1a22cadbdb' or "a"='7f626e0123';]]). You have to add the field names and types of aaa before doing this, with the format() function.
For me this work fine, but need make check for return from first select:
local res = {}
for k, v in pairs (box.space.email:select({email})[1]) do
if type(v) == 'string' then
table.insert(res, box.space.logs:select({v})[1])
end
end

Efficiency of my function with Lua tables

I have a question about the way I put together this piece of Lua code.
Say, there is a function like the one below, containing 200 myTable tables, where the names are ordered alphabetically:
function loadTable(x)
local myTable
if x == "aaron" then myTable = {1,2,3,4,5,6,7,8,9,0}
elseif x == "bobby" then myTable = {1,3,3,4,5,8,7,8,9,1}
elseif x == "cory" then myTable = {1,2,3,3,3,6,7,8,9,2}
elseif x == "devin" then myTable = {1,2,3,4,5,2,3,4,9,0}
...
else
print("table not available")
end
return myTable
end
and now I want to find the table corresponding to x == "zac" (which happens to be somewhere at the end). I use this line of code:
local foundTable = loadTable("zac")
Isnt this like not efficient at all? If it has to find the table at the very end of the function it has to go through all the previous lines of code. Is there some way to code this more efficiently in lua and find the correct table faster? ?
This can become a lot faster by using... a table!
Simply make a table whose keys are the name of the person and the values are the table you want to load, like this:
local tables = {
john = {1,2,3,4,5,6,7,8,9,0},
peter = {1,3,3,4,5,8,7,8,9,1},
william = {1,2,3,3,3,6,7,8,9,2},
victoria = {1,2,3,4,5,2,3,4,9,0}
--...
}
Then, instead of calling loadTable("richard") simply use tables["richard"] or tables.richard if the key is a valid identifier

Lua - Sorting a table alphabetically

I have a table that is filled with random content that a user enters. I want my users to be able to rapidly search through this table, and one way of facilitating their search is by sorting the table alphabetically. Originally, the table looked something like this:
myTable = {
Zebra = "black and white",
Apple = "I love them!",
Coin = "25cents"
}
I was able to implement a pairsByKeys() function which allowed me to output the tables contents in alphabetical order, but not to store them that way. Because of the way the searching is setup, the table itself needs to be in alphabetical order.
function pairsByKeys (t, f)
local a = {}
for n in pairs(t) do
table.insert(a, n)
end
table.sort(a, f)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
end
end
return iter
end
After a time I came to understand (perhaps incorrectly - you tell me) that non-numerically indexed tables cannot be sorted alphabetically. So then I started thinking of ways around that - one way I thought of is sorting the table and then putting each value into a numerically indexed array, something like below:
myTable = {
[1] = { Apple = "I love them!" },
[2] = { Coin = "25cents" },
[3] = { Zebra = "black and white" },
}
In principle, I feel this should work, but for some reason I am having difficulty with it. My table does not appear to be sorting. Here is the function I use, with the above function, to sort the table:
SortFunc = function ()
local newtbl = {}
local t = {}
for title,value in pairsByKeys(myTable) do
newtbl[title] = value
tinsert(t,newtbl[title])
end
myTable = t
end
myTable still does not end up being sorted. Why?
Lua's table can be hybrid. For numerical keys, starting at 1, it uses a vector and for other keys it uses a hash.
For example, {1="foo", 2="bar", 4="hey", my="name"}
1 & 2, will be placed in a vector, 4 & my will be placed in a hashtable. 4 broke the sequence and that's the reason for including it into the hashtable.
For information on how to sort Lua's table take a look here: 19.3 - Sort
Your new table needs consecutive integer keys and needs values themselves to be tables. So you want something on this order:
SortFunc = function (myTable)
local t = {}
for title,value in pairsByKeys(myTable) do
table.insert(t, { title = title, value = value })
end
myTable = t
return myTable
end
This assumes that pairsByKeys does what I think it does...

Resources