user2176999
user2176999

Reputation: 43

Trigger Redis HMSET with LUA

I have need to call Redis HMSET with a Redis Lua script. Here is a coffee script:

redis = require("redis")
client = redis.createClient();

lua_script = "\n
-- here is the problem\n
local res = redis.call('hmset', KEYS[1],ARGV[1])\n
print (res)\n
-- create secondary indexes\n
--\n
--\n
return 'Success'\n
"

client.on 'ready', () ->
  console.log 'Redis is ready'
  client.flushall()
  client.send_command("script", ["flush"])

  args = new Array(3)

  args[0] = '1111-1114'
  args[1] = 'id'
  args[2] = '111'
  callback = null
  #client.send_command("hmset", args, callback) # this works

  client.eval lua_script, 1, args, (err, res) ->
    console.log 'Result: ' + res

What is the correct syntax / pattern to call HMSET in the LUA script? BTW - I am aware of the redis.HMSET command.

Upvotes: 1

Views: 2700

Answers (1)

catwell
catwell

Reputation: 7020

First, are you sure you are using eval in your CoffeeScript Redis library correctly? You are apparently passing three arguments: the script, the number of keys and an array. I suspect this is not how it works. If this is node_redis, either everything or nothing must be in the array, so try:

args = new Array(5)

args[0] = lua_script
args[1] = 1
args[2] = '1111-1114'
args[3] = 'id'
args[4] = '111'
callback = null

client.eval args, (err, res) ->
  console.log 'Result: ' + res

(There is probably a nicer syntax but I don't know CoffeeScript.)

Secondly, in this example you are trying to HMSET a single field/value pair:

HMSET lua_script 1111-1114 id 111

Actually you could replace HMSET by HSET here, but let's make it work first.

In this line:

local res = redis.call('hmset', KEYS[1], ARGV[1])

You are only calling HMSET with two arguments, the key containing the hash and the field. You need to add the value which is the second argument:

local res = redis.call('hmset', KEYS[1], ARGV[1], ARGV[2])

This will make your example work, but what if you want to actually set multiple fields (which is the goal of MHSET) like so?

HMSET lua_script 1111-1114 id 111 id2 222

In CoffeeScript you would write:

args = new Array(7)

args[0] = lua_script
args[1] = 1
args[2] = '1111-1114'
args[3] = 'id'
args[4] = '111'
args[5] = 'id2'
args[6] = '222'
callback = null

client.eval args, (err, res) ->
  console.log 'Result: ' + res

... but now you have four elements in ARGV to pass to redis.call in Lua. Actually you have to pass all the elements of ARGV, and this is called unpack() in Lua:

local res = redis.call('hmset', KEYS[1], unpack(ARGV))

The only issue with using unpack() is that if you have a real lot of elements in ARGV (thousands) it can break because it will overflow the stack, in which case you should use a loop in the Lua script to call HMSET on slices of ARGV, but you should probably not worry about that for now...

Upvotes: 1

Related Questions