2013-05-01 3 views
3

Я работаю с базой данных redis в node.js, используя node_redis. Вот краткий пример структуры, подобной той, которую я использую.Узел Redis: как фильтровать отсортированный набор ключей и извлекать каждый хэш-хэнд значений за один вызов

hmset('user:1234', 
    'user_id', 1234, 
    'user_name', billy, 
    'user_age', 16); 
//add user to group 1 store their id with their age as their score 
zadd(['group:1:users_by_age', 16, user:1234]); 

hmset('user:1235', 
    'user_id', 1235, 
    'user_name', jake, 
    'user_age', 21); 
//add user to group 1 store their id with their age as their score 
zadd(['group:1:users_by_age', 21, user:1235]); 

Теперь давайте говорить, что я хотел бы получить все пользовательские данные для пользователей в возрасте старше 18 лет в группе: 1

Я знаю, что могу получить ключи пользователей по телефону

postClient.zrangebyscore( 
    [ 'group:1:users_by_age', '18', '+inf'], 
    function(err, results){ 
     console.log(results); 
    } 
); 

Где Я заблудился, как получить все пользовательские объекты сразу? Чтобы сделать это еще на один шаг, можно ли как zrangebyscore, так и получить все пользовательские объекты в один звонок?

ответ

1

Чтобы сделать это еще на один шаг, можно ли как zrangebyscore, так и получить все пользовательские объекты за один звонок?

Я не верю, что вы можете. Команда SORT имеет встроенную функциональность GET, которая позволяет вам делать такую ​​вещь за один вызов, но нет способа передать результаты ZRANGEBYSCORE в SORT (запрет на сохранение его во временном ключе, а затем использование SORT на этом ключе).

Существует также естественный способ получить несколько хэшей в один звонок.

С вашей текущей реализации, с учетом этих ограничений, вы можете получить все пользователи с несколькими, например:

postClient.zrangebyscore([...], function (err, results) { 
    var multi = postClient.multi(); 
    for (var i=0; i<results.length; i++){ 
    multi.hgetall(results[i]); 
    } 
    multi.exec(function(err, users){ 
    console.log(users); 
    }); 
}); 

Вы могли сделать это с luascript хотя, извлекая список ключей и итерацию по нему, вызывая hmget или hgetall на каждом ключе.

Я делаю что-то подобное в следующем примере, используя hmget и определенные ключи.

Очевидное заявление об ответственности: Я не программист lua. Краткое объяснение: сценарий принимает начальный и конечный диапазон для возраста пользователя, затем любое количество хэш-ключей, которое он использует для hmget для каждого пользовательского ключа, и добавляя все это к массиву, который будет завернут как пользовательские объекты обратно в javascript ,

var script = '\ 
local keys = redis.call("ZRANGEBYSCORE", KEYS[1], ARGV[1], ARGV[2]); \ 
if not keys then return {} end; \ 
local users, attrs = {}, {} \ 
for i=3,#ARGV do \ 
    table.insert(attrs, ARGV[i]) \ 
end \ 
for i,key in pairs(keys) do \ 
    local vals = redis.call("HMGET", key, unpack(attrs)); \ 
    if vals then \ 
    for j,val in pairs(vals) do \ 
     table.insert(users, val) \ 
    end \ 
    end \ 
end \ 
return users \ 
'; 

// The rest of this you'd probably want to wrap up in an async function, 
// e.g `getUsersByRange` 

// specify the user attributes you want 
var attrs = ["id", "name", "age"]; 

// specify the range 
var range = [18, "+INF"]; 

// get the attributes length, used to build the user objects 
var attrlen = attrs.length; 

// wrap up the params 
var params = [script, 1, "users_by_age"].concat(range).concat(attrs); 

// retrieve the user attributes in the form of [a1, a2, a3, a1, a2, a3, ... ], 
// then collate them into an array of user objects like hgetall would return. 
postClient.eval(params, function (err, res) { 
    var users = [], i, j, k; 
    for (i=0, j=0; i<res.length; i+=attrlen, j++) { 
    users[j] = {}; 
    for (k=0; k<attrlen; k++) { 
     users[j][attrs[k]] = res[i+k]; 
    } 

    // this should be a list of users 
    console.log(users); 
    } 
}); 

Обратите внимание, что это было бы тривиально обрабатывать пользователь обратно в объекты внутри скрипта Lua, но когда преобразуются обратно в REDIS структур данных, таблицы Lua стали Redis мульти сыпучих ответами (массивы), а структура будет Потерянный. Из-за этого необходимо преобразовать многовальный ответ в пользовательские объекты обратно в javascript.

+0

Если мне нужно использовать мульти, все равно, что я могу получить все данные сразу, когда я, наконец, отправлю его? (IE без необходимости иметь дело с обратным обращением) – Billy

+1

Не обойдя то же самое в сценарии lua. В противном случае вы смотрите на 2 запроса, получая ключи из набора, а затем отправляете мульти, чтобы получить хеши. В luascript вы можете пропустить multi и просто запустить hgetalls самостоятельно, упаковать их и вернуть весь список, а затем обработать их обратно вместе аналогично тому, как я это делаю во втором примере. (Обычно node_redis автоматически сопоставляет hgetalls с объектами) – numbers1311407