更进一步,是否可以一次调用 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 中的用户对象。