Как проверить nil/null в Luis cjson из Redis?
У меня есть скрипт 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
1 ответ
TL;DR для значений, возвращаемых cjson.decode()
использовать cjson.null
сравнить с JSON null
значение.
Пояснение: Lua использует nil
в таблицах отмечать удаленные записи. Если JSONinc null
с были переведены в сумасшедший nil
s, декодированные объекты будут повреждены. Следовательно, библиотека cjson использует упрощенный тип пользовательских данных для представления null
/nil
,
Ваши 'call_data' имеют поле 'date_created', которое является нулевым - это вызывает ошибку.
Самое смешное, что Redis, как и Lua, не будет хранить значения 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))
PS, если хотите, посмотрите на ReJSON, который я написал - он призван помочь вам в том, что вы пытаетесь сделать.