How to use redis.call("mget") using lua - redis

I have following scnario using lua with redis script
local valuesForMset = {"key_1", "0", "key_2", "0"};
redis.call("MSET", unpack(valuesForMset))
I would expect MGET key_1 to return 0 but instead it returns nil . I have already tried following as well
local valuesForMset = {"key_1", "key_2"};
redis.call("MSET", unpack(valuesForMset))
And result is same. Has anyone used lua for MSET? If yes how did you achieve setting key-value with MSET.
Thank you in advance.

You have not created a table with values, you have created the Lua equivalent of a set in this line
local valuesForMset = {"key_1", "0", "key_2", "0"};
To be a Lua table with key-value pairs it should be
local valuesForMset = {}
valuesForMset["key_1"] = 0
valuesForMset["key_2"] = 0
Your original code created a table with four keys all with the nil value.

Related

Redis using members of sorted list to delete external keys

Using sort one can sort a set and get external keys using results from the sort component of query.
By way of example:
If the external key/value are defined as various keys using the pattern:itemkey:<somestring>
And a sorted list has list of the members then issuing command sort <lists key> by nosort get itemkey:* would get the values of the referenced keys.
I would like to be able to sort through a sorted list and delete these individual keys but it appears that sort <key> by nosort del itemkey:* is not supported.
Any suggestions on how to get list of values stored in a set and then delete the external keys?
Obviously I can do this with two commands, first getting the list of values and then by iterating through list call the delete function - but this is not desirable as I requite atomic operation.
To ensure atomic operation one can use either transactions or redis' lua scripts. For efficiency I decided to go with using script. This way the entire script is completed before next redis action/request is processed.
In code snippet below. I used loadScript in order to store script redis side reducing traffic with every call, the response from loadScript is then used as identifier to Jedis's evalsha command.
Using Scala (Note Jedis is a Java library, hence the .asJava):
val scriptClearIndexRecipe = """local names = redis.call('SORT', KEYS[1]);
| for i, k in ipairs(names) do
| redis.call('DEL', "index:recipe:"..k)
| end;
| redis.call('DEL', KEYS[1]);
| return 0;""".stripMargin
def loadScript(script: String): String = client.scriptLoad(script)
def eval(luaSHA: String, keys: List[String], args: List[String]): AnyRef = {
client.evalsha(luaSHA, keys.asJava, args.asJava)
}

PyMongo checking if entry is already in array

I want to have an array of IPs that went to x webpage and have them in an array. However right now everytime an IP connects it gets added, if multiple people connect multiple times there'll be many duplicates.
Currently I'm just using
query = {"_id": paste_id, "ip": {"$ne": real_ip}
collection.update_one(query, {"$push": {"ip": ip}})
but that (logically) just pushes the entry into the array, what'd be a way to check if ip is already in the array?
UPDATED ANSWER
The updated code you posted is checking for real_ip and then inserting ip; so you're not checking the item your actually updating.
My original answer below still stands as the correct approach; however this complete example demonstrates attempting to insert the real_ip 5 times and it shows the value is only inserted once:
from pymongo import MongoClient
collection = MongoClient()['mydatabase'].collection
result = collection.insert_one({'ip': []})
paste_id = result.inserted_id
real_ip = '1.2.3.4'
for i in range(5):
query = {"_id": paste_id, "ip": {"$ne": real_ip}}
collection.update_one(query, {"$push": {"ip": real_ip}})
print(list(collection.find()))
prints:
[{'_id': ObjectId('5feefdb862e2ed3ea952a035'), 'ip': ['1.2.3.4']}]
ORIGINAL ANSWER
Add a check that the IP is not already in the ip array, e.g.
query = {'ip': {'$ne': ip}}

Using a variable content to generate a variable name

I have a script for a game server, and I'm stuck in some shit that look easy to solve
Exists a variable which receive content dynamically based on user action, so we will name this variable: example, and attrib some random value
local example = Potato
Then I have a function which sends a message to a discord webhook
SendWebhookMessage(varNAME, "Message content")
Where varname is the variable containing the link of the webhook.
I want to use the content of variable example to generate the variable name like
webhook_ds_example
So in this case it will be
webhook_ds_potato
Hope you guys could understand and help to solve
local menu = { name = "Baú" }
local cb_take = function(idname)
local citem = chest.items[idname]
local amount = vRP.prompt(source,"Quantidade:","")
amount = parseInt(amount)
if amount >= 0 and amount <= citem.amount then
local new_weight = vRP.getInventoryWeight(user_id)+vRP.getItemWeight(idname)*amount
if new_weight <= vRP.getInventoryMaxWeight(user_id) then
citem.amount = citem.amount - amount
local temp = os.date("%x %X")
vRP.logs("savedata/bau.txt","Bau: "..name.." [ID]: "..user_id.." /"..temp.." [FUNÇÃO]: Retirar / [ITEM]: "..idname.." / [QTD]: "..amount)
local webhook_bau_fac1 = ""
local webhook_bau_fac2 = ""
local webhook_bau_fac3 = ""
local webhook_bau_fac4 = ""
SendWebhookMessage(webhook_bau_..name,"```prolog\n[ID]: "..user_id.." "..identity.name.." "..identity.firstname.." \n[GUARDOU]: "..vRP.format(parseInt(amount)).." "..vRP.itemNameList(itemName).." \n[BAU]: "..chestName.." "..os.date("\n[Data]: %d/%m/%Y [Hora]: %H:%M:%S").." \r```")
You are looking for tables, which let you store lots of different named values in one variable.
local webhook_bau -- make a variable
-- create a table with 4 entries, put it in the variable
webhook_bau = {fac1="", fac2="", fac3="", fac4=""}
-- if you want to start with an empty table, use {} instead
-- change one of them based on the name
webhook_bau[name] = "something"
-- use one of the entries based on the name
SendWebhookMessage(webhook_bau[name], "whatever you want to send")
Table entries "magically" appear when you use them, you don't have to create them first. If you access an entry that doesn't exist, you will read the value nil. You can also delete an entry by putting nil in the entry.
In the example you provided, you have:
SendWebhookMessage(webhook_bau_..name,"```prolog\n[ID]: "..user_id.." "..identity.name.." "..identity.firstname.." \n[GUARDOU]: "..vRP.format(parseInt(amount)).." "..vRP.itemNameList(itemName).." \n[BAU]: "..chestName.." "..os.date("\n[Data]: %d/%m/%Y [Hora]: %H:%M:%S").." \r```")
You are missing quotes around webhook_bau_ which would result in an error trying to concatenate a nil variable.
I'm also not seeing where name is set (only menu.name), so I'm assuming you have that elsewhere in your program, if not, that will also be nil, so just make sure that is set somewhere as well.

Terraform: How Do I Setup a Resource Based on Configuration

So here is what I want as a module in Pseudo Code:
IF UseCustom, Create AWS Launch Config With One Custom EBS Device and One Generic EBS Device
ELSE Create AWS Launch Config With One Generic EBS Device
I am aware that I can use the 'count' function within a resource to decide whether it is created or not... So I currently have:
resource aws_launch_configuration "basic_launch_config" {
count = var.boolean ? 0 : 1
blah
}
resource aws_launch_configuration "custom_launch_config" {
count = var.boolean ? 1 : 0
blah
blah
}
Which is great, now it creates the right Launch configuration based on my 'boolean' variable... But in order to then create the AutoScalingGroup using that Launch Configuration, I need the Launch Configuration Name. I know what you're thinking, just output it and grab it, you moron! Well of course I'm outputting it:
output "name" {
description = "The Name of the Default Launch Configuration"
value = aws_launch_configuration.basic_launch_config.*.name
}
output "name" {
description = "The Name of the Custom Launch Configuration"
value = aws_launch_configuration.custom_launch_config.*.name
}
But how the heck do I know from the higher area that I'm calling the module that creates the Launch Configuration and Then the Auto Scaling Group which output to use for passing into the ASG???
Is there a different way to grab the value I want that I'm overlooking? I'm new to Terraform and the whole no real conditional thing is really throwing me for a loop.
Terraform: How to conditionally assign an EBS volume to an ECS Cluster
This seemed to be the cleanest way I could find, using a ternary operator:
output "name {
description = "The Name of the Launch Configuration"
value = "${(var.booleanVar) == 0 ? aws_launch_configuration.default_launch_config.*.name : aws_launch_configuration.custom_launch_config.*.name}
}
Let me know if there is a better way!
You can use the same variable you used to decide which resource to enable to select the appropriate result:
output "name" {
value = var.boolean ? aws_launch_configuration.custom_launch_config[0].name : aws_launch_configuration.basic_launch_config[0].name
}
Another option, which is a little more terse but arguably also a little less clear to a future reader, is to exploit the fact that you will always have one list of zero elements and one list with one elements, like this:
output "name" {
value = concat(
aws_launch_configuration.basic_launch_config[*].name,
aws_launch_configuration.custom_launch_config[*].name,
)[0]
}
Concatenating these two lists will always produce a single-item list due to how the count expressions are written, and so we can use [0] to take that single item and return it.

Is there a command in Redis for HASH data structure similar to MGET?

I need to get in one call all data fields for a set of known REDIS hash keys. I've used MGET for string keys such as :
MGET key [key ...]
Available since 1.0.0.
Time complexity: O(N) where N is the number of keys to retrieve.
Returns the values of all specified keys. For every key that does not hold a string value or does not exist, the special value nil is returned. Because of this, the operation never fails.
HMGET only brings all fields for one key. I need many keys all fields by key.
There is no command like that, redis hashes work within the hash, so HMGET work inside one hash and give all the fields in that hash. There is no way to access all the fields in multiple hashes at ones.
However you can user several HMGET on each hash and get all the fields. you can pipeline these commands to execute in a one go.
Option 1
Ex. implementation in pseudo code
Pipeline p
List<String> = p.hgetall('key1', fields...);
List<String> = p.hgetall('key2', fields...);
List<String> = p.hgetall('key3', fields...);
p.exec();
Option 2
Other option is to write a LUA script and call that using EVAL
local array = {}
local keys = redis.call('KEYS', '<your pattern>')
for _,key in ipairs(keys) do
local val = redis.call('HGETALL', key)
array[#array + 1] = val
end
return array
Call the lua sctipt
redis-cli EVAL "$(cat test.lua)" 0
1) 1) "field1"
2) "val"
2) 1) "field1"
2) "val"
3) "field2"
4) "val2"
As noted in another answer, there's no built in way but there more workarounds besides a transaction.
Option 1: use a Lua script (i.e. EVAL "..." 3 myhash1 myhash2 myhash3 myfield)
local r = {}
while (#KEYS > 0) do
local k = table.remove(KEYS,1)
r[#r+1] = redis.call('HGET', k, ARGV[1])
end
return r
Option 2: write a Redis module
Out of scope as a an answer :)