我正在使用node.js和redis。我有一堆带有密钥的redis数据库。像这样:
用户/克里斯/药水 用户/皮特/药水 用户/克里斯/种族 用户/皮特/种族 用户/克里斯/武器 用户/皮特/武器
我想做一个redis调用,它检索所有用户统计信息,将统计信息放入JS对象,然后将其传递给客户端,以便在浏览器中显示字符统计信息。使用javascript我将 u 中的用户名chris注入redis调用,如下所示:
KEYS user/u/*
返回:
1) "user/chris/weapon"
2) "user/chris/race"
3) "user/chris/potion"
现在我可以遍历这些结果,使用GET获取每个键的值,并创建一个javascript对象。看起来超级简单,所以我编写了代码。我很快就遇到了使用forEach的问题:
var redis = require('redis');
var client = redis.createClient();
exports.getUserObject = function(requesteduser, callback) {
var userstats = {}; // the object to hold the user stats once retrieved from the db
client.KEYS('user/' + requesteduser + '/*', function(err, replies) {
replies.forEach(function (reply, i) {
client.GET(reply, function(err, value) {
// get the key name so we can populate a js object
var n = reply.lastIndexOf('/');
var key = reply.substring(n + 1, reply.length);
userstats[key] = value;
console.dir(userstats);
callback(null, userstats); // parent expects (err, userstats)
});
});
});
}
运行时,输出如下:
{ weapon: 'twosword' }
{ weapon: 'twosword', race: 'elf' }
{ weapon: 'twosword', race: 'elf', potion: 'mana' }
callback(null, userstats)
被召唤三次。多次调用回调将会有问题,因为最终回调将触发数据被发送到客户端。
我想我知道发生了什么。 client.GET
被运行了三次因为我问过它。 replies
数组有三个元素,因此每次结果进入client.GET
时,都会调用回调。
我需要做的是让forEach循环完成所有redis键的迭代,一旦完成,就调用一次回调。我尝试首先使用promises解决此问题,然后使用async解决此问题,因为async具有async.each。我两次都遇到了解决问题的困难。我现在回到原点,我确信我必须做一些与forEach不同的事情来取得进展。
我该如何做到这一点?
答案 0 :(得分:2)
由于您正在迭代replies
,因此您可以检查何时到达最后一个元素,并且仅在该实例中调用callback
。
client.KEYS('user/' + requesteduser + '/*', function(err, replies) {
replies.forEach(function (reply, i) {
client.GET(reply, function(err, value) {
// get the key name so we can populate a js object
var n = reply.lastIndexOf('/');
var key = reply.substring(n + 1, reply.length);
userstats[key] = value;
console.dir(userstats);
if (i == replies.length-1) callback(null, userstats); // parent expects (err, userstats)
});
});
});
答案 1 :(得分:2)
我知道帮助@Grimtech有点晚了,但我会留下我最终到达这里的其他人的意见:
首先,我宁愿以不同的方式模仿@ Grimtech的问题。像这样:
client.hmset("user:chris", "weapon", "some weapon", "race", "some race", "potion", "some potion");
client.hmset("user:pete", "weapon", "same weapon", "race", "other race", "potion", "other potion");
然后我会在Node中返回一个 json 的方法,假设我可以有一个以“user:chris”开头的键:
router.get('/users/:user_id', function(req, res, next) {
var response = [];
var client = redis.createClient();
client.keys("user:" + req.params.user_id + "*", function (err, users) {
users.forEach(function (key, pos) {
client.hgetall(key, function (err, user) {
response.push(user);
if (pos === users.length - 1) {
res.json(response);
client.quit();
}
});
});
});
});
if(pos === users.length - 1)解决了异步问题。
返回的json将具有所有“user:chris”属性,因此您可以在客户端浏览器中执行任何操作。