Reputation: 17072
I did some node.js code to retrieve data within a redis DB but I'm not really happy and I'd like to improve it...
Basically, I have a record "people" in my redis db. From "people" I get a list of "person:i" (i being an integer) and, for each "person:i", I make an additional query to retrieve the hash with key "person:i".
This is how I do it:
db.smembers("people", function(err1, people){
var jsonObj;
var jsonArr = [];
if(!err1) {
var i = 0;
res.writeHead(200, {'content-type': 'application/json'});
// people will provide a list like [person:1, person:2, ..., person:n]
people.forEach(function(person){
// In redis I get the hash with key "person:i"
db.hgetall(person, function(err2,obj){
if(!err2){
// Add person into array
jsonArr.push({ "id" : person.substring(7), "lastname" : obj["lastname"], "firstname" : obj["firstname"]});
// I'm not happy with this part where I check if I reached the last item of people array....
i = i + 1;
if(i == people.length){
res.write(JSON.stringify(jsonArr));
res.end();
}
} else {
var jsonObj = { "error" : "database error", "message" : "Cannot get hash " + person};
res.write(JSON.stringify(jsonObj));
res.end();
}
});
});
} else {
jsonObj = { "error" : "database error", "message" : err1.message };
res.writeHead(200, {'content-type': 'application/json'});
res.write(JSON.stringify(jsonObj));
res.end();
}
});
What would be the cleanest (at least a cleaner) way to do it ?
Upvotes: 1
Views: 1536
Reputation: 5886
What you're looking for is an asynchronous control flow system. An example would be Step or streamline.js.
An alternative would be to abstract the process, creating a data model for Person that would fetch an individual person object, and a People model that's a collection of Persons that would include a method for fetching multiple people following the structure you're using.
Edit: I found a comprehensive listing of node compatible control flow/async libraries: https://github.com/joyent/node/wiki/modules#wiki-async-flow
Edit: After reviewing your code I've thought of another alternative method which is fairly specific to this case, but doesn't directly address the control flow nature of the question.
By altering your schema to store only the ID of the person in the people
key you open yourself up to using redis's SORT
command, which would enable the entire collection to be fetched in a single command. To do this in redis:
> SADD people 1 2 3 4
> HMSET person:1 firstname John lastname Smith
> HMSET person:2 firstname Jane lastname Smith
> HMSET person:3 firstname John lastname Doe
> HMSET person:4 firstname Jane lastname Doe
> SORT people GET # GET person:*->firstname GET person:*->lastname
1) "1"
2) "Jane"
3) "Doe"
4) "2"
5) "Jane"
6) "Smith"
7) "3"
8) "John"
9) "Doe"
10) "4"
11) "Jane"
12) "Doe"
This has the added benefit of memory savings in the people
key, and enables pagination/sorting via the SORT
command's by
and limit
options.
Upvotes: 4