3

我正在使用node_redis在 node.js 中使用 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 并获取所有用户对象?

4

1 回答 1

3

更进一步,是否可以一次调用 zrangebyscore 并获取所有用户对象?

我不相信你可以。SORT 命令具有内置的 GET 功能,允许您在一次调用中执行此类操作,但无法将 ZRANGEBYSCORE 的结果通过管道传输到 SORT(除非将其存储在临时键中,然后在该键上使用 SORT)。

也没有自然的方法可以在一次调用中检索多个哈希值。

在您当前的实现中,考虑到这些限制,您可能会让所有用户都使用 multi,例如:

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 中的用户对象。

于 2013-05-01T19:06:19.217 回答