如何在 Redis 的 Lua cjson 中检查 nil/null?

我有一个带有以下代码块的 lua 脚本:

local call_data     = cjson.decode(ARGV[1])
local other_data    = cjson.decode(ARGV[2])
local data          = {}
local next          = next
local populate_data = function(source)
  if next(source) == nil then
    return
  end

  for property,value in pairs(source) do
    redis.call('HSET', KEYS[2], property, value)
  end
end
populate_data(call_data)
populate_data(other_data)

当我尝试使用以下命令运行脚本时,keys 和 argv 分别为:

redis-cli --eval dialed.lua "inflight_stats:18" "calls:AC443d7a8111a96ba8074f54a71f0521ce:CA1ec49703eee1959471c71506f43bb42e:dialed" , "{\"from\":\"+18035224181\",\"to\":\"+919943413333\",\"sid\":\"CA1ec49703eee1959471c71506f43bb42e\",\"status\":\"queued\",\"direction\":\"outbound-api\",\"date_created\":null,\"account_sid\":\"AC443d8a8111a96ba8074f54a71f0521ce\"}" "{\"phone\":\"919943413333\",\"campaign_id\":18,\"caller_session_sid\":\"CA828b163153bf5cc301ef5285e38925f9\"}" 0

错误: -

(error) ERR Error running script (call to f_08dcc69ee8baa0200e0cf552948ab4bc338c9978): @user_script:11: @user_script: 11: Lua redis() command arguments must be strings or integers
点赞
用户3160475
用户3160475

TL;DR 对于 cjson.decode() 返回的值,在比较 JSON 的 null 值时,请使用 cjson.null

解释:Lua 将删除的条目标记为表中的 nil。如果 JSON 中的 null 被转换为 Lunatic nil,则解码后的对象将是损坏的。因此,cjson 库使用轻量级的用户数据类型来表示 null/ nil

你的 call_data 有一个 date_created 字段为 null,这会导致错误。

有趣的是,像 Lua 一样,Redis 不会存储空值/nil,因此你必须要么忽略 null 值,要么在 Redis 中使用特殊值来标记它们。

假设你会忽略它们,以下是一种解决方法:

local call_data     = cjson.decode(ARGV[1])
local other_data    = cjson.decode(ARGV[2])
local data          = {}
local next          = next
local null          = cjson.null
local populate_data = function(source)
  if next(source) == nil then
    return
  end

  for property,value in pairs(source) do
    if value ~= null then
      redis.call('HSET', KEYS[2], property, value)
    end
  end
end
populate_data(call_data)
populate_data(other_data)

此外,一个小优化是批量更新,例如:

  local payload = {}
  for property,value in pairs(source) do
    if value ~= null then
      table.insert(payload, property)
      table.insert(payload, value)
    end
  end
  redis.call('HSET', KEYS[2], unpack(payload))

附注:如果你愿意,请查看我编写的 ReJSON,它旨在帮助你完成你正在尝试的操作。

2018-10-20 12:47:14