Search code examples
luaredisnode-redis

How to return a table with string keyed key value pairs from a lua script to node js?


I have a lua script. I am running from node.js and my script is returning a lua table with key value pairs in it like { '1': 15, '2': 35 }. In node I am getting an empty array. However if I return arrayName['1']. It gives me proper value 15. What am I doing wrong here. I am using node_redis client for node to redis. Diffrent files are given below.

Lua Script - groupBy.lua

local db = "";
local table = "students";
local groupBy = "class";
local aggregate = "marks";

local a = {};
local marksGroupedByClass = {};
for i = 1, 4 do
    local dataArr = redis.call("hgetall", db..table..":"..i);
    local dataObj = {};
    for i = 1, #dataArr, 2 do
        dataObj[dataArr[i]] = dataArr[i+1];
    end
    if a[dataObj["class"]] then
        a[dataObj["class"]] = a[dataObj["class"]] + dataObj["marks"]
    else
        a[dataObj["class"]] = dataObj["marks"]
    end
end

return a['2'];      -- This returns proper value 35
-- return a;            This returns empty array to node

node file - luaExec.js

let fs = require('fs');
let redis  = require('redis');
let client = redis.createClient();

client.on("error", cb);

function cb(err) {
    console.log("Error " + err);
}

client.eval(fs.readFileSync('groupBy.lua'), 0, (err, replies) => {
    if(err) cb(err);
    console.log(replies);
})

client.quit();

I saved my data with this script - saveStudentData.lua

redis.call("hmset","students:1", "name", "A", "class", 1, "marks", 5 );
redis.call("hmset","students:2", "name", "B", "class", 1, "marks", 10 );
redis.call("hmset","students:3", "name", "C", "class", 2, "marks", 15 );
redis.call("hmset","students:4", "name", "D", "class", 2, "marks", 20 );

Solution

  • TL;DR you can't.

    Redis has no support for a key-value type of response (although there are talks of changing that in the next version of the protocol RESP3).

    Thus, returning an associative array from Lua (a table with kv pairs) results in an empty array as you've found out. What you'll need to do is flatten it, e.g.:

    ...
    local reply = {} for k, v in pairs(a) do
      table.insert(reply, k)
      table.insert(reply, v)
    end
    
    return reply
    

    Or simply prepare a flattened in the preceding loop. Lastly, your client will have to be aware of this format and recompose the object from it, should that be needed.