如何在Redis中用cmsgpack和Lua存储一个带空值的json?

问题描述 投票:0回答:1

我一直在阅读关于cjson的文档,知道null值转换为 cjson.null 值(因为在 Lua 表中没有办法存储 nil。如果我使用cjson.decode和cjson.encode的话,效果很好。

然而,当我尝试用 cmsgpack,空值的键不存在。我使用类似这样的代码 一个.

你是如何解决这个问题的?你是用一个特殊的值来替换null值(在调用cmspack.pack之前,{isnull: true},然后再把{isnull: true}替换回null)还是用其他技术?

json redis lua msgpack
1个回答
0
投票

我做了一个快速的研究,没有找到任何 msgpack 库来处理 null 值的哈希表。不过我并不是说不存在这样的库。

我选择了另一种方法。由于 lua-cmsgpack 不做任何特殊处理 null 解码MessagePack二进制数据时的值和 nil 值只在表中有问题,我们可以为哈希→表解码器增加一些特殊情况的代码。

其实,这个补丁是很简单的。

--- a/lua_cmsgpack.c
+++ b/lua_cmsgpack.c
@@ -565,6 +565,10 @@ void mp_decode_to_lua_hash(lua_State *L, mp_cur *c, size_t len) {
         mp_decode_to_lua_type(L,c); /* key */
         if (c->err) return;
         mp_decode_to_lua_type(L,c); /* value */
+        if (lua_isnil(L, -1)) {
+            lua_pop(L, 1);
+            lua_pushlightuserdata(L, NULL);
+        }
         if (c->err) return;
         lua_settable(L,-3);
     }

这里的第二个调用 mp_decode_to_lua_type 转换一个哈希条目 价值 到一个对应的Lua类型值,当该值为 nil (即: null 在MessagePack中),我们用一个轻量级的用户数据来代替它(NULL 指针)。) 同样的用户数据(NULL 指针)被用作 cjson.null 值。

我们不需要给编码器打补丁,因为它可以将任何不支持的值,包括任何用户数据编码为 null,也就是说,你可以使用 cjson.null 用户数据来代表 null 值(cjson.decode就是这样做的)。当哈希值被解码后,你会得到相同的userdata。

同样的技巧也可以应用于类似数组的表,但如果你知道表的大小,就没有必要了--你可以从第一个索引到最后一个索引对表进行迭代。

local cjson = require('cjson')
local cmsgpack = require('cmsgpack')

local encoded_hash = cmsgpack.pack({k1 = nil, k2 = cjson.null, k3 = 'baz'})
local decoded_hash = cmsgpack.unpack(encoded_hash)
print('decoded_hash.k2 == cjson.null?', decoded_hash.k2 == cjson.null)
for k, v in pairs(decoded_hash) do
    print(k, '->', v)
end

local encoded_array = cmsgpack.pack({'foo', nil, cjson.null, 'bar'})
local decoded_array = cmsgpack.unpack(encoded_array)
print('#decoded_array =', #decoded_array)
for i = 1, 4 do
    print(i, '->', decoded_array[i])
end

输出。

decoded_hash.k2 == cjson.null?  true
k3  ->  baz
k2  ->  userdata: (nil)
#decoded_array =    4
1   ->  foo
2   ->  nil
3   ->  userdata: (nil)
4   ->  bar

多亏了LuaRocks,我们甚至不需要支持库的fork就能完成这样一个琐碎的补丁。补丁可以直接包含在rockspec文件中。我用修改后的rockspec创建了一个gist。https:/gist.github.comun-defd6b97f5ef6b47edda7f65e0c6144663c

你可以用下面的命令安装一个打过补丁的库。

luarocks install https://gist.github.com/un-def/d6b97f5ef6b47edda7f65e0c6144663c/raw/8fe2f1ad70c75bfe2532a1f4cf9213f4e28423d3/lua-cmsgpack-0.4.0-0.rockspec
© www.soinside.com 2019 - 2024. All rights reserved.