I really want to like node.js with redis, but I can’t conquer asynchronicity. Again I have what is a simple task in a traditional database and language. My question is more about accomplishing control flow and logic in asynchronous database fetching than whether my problem-solving approach is optimal or not.
Here’s what I’m trying to do: I have redis keys made up of words, let’s just say car and card. Now, given an input string, I want to know what the longest substring is, that matches a key in redis. I only need to check substrings starting from position 0 of the given string, so the complexity is low.
Example: cardinal has the key card in it, and also car, but card is longer. Cape does not match either key.
My approach is: start with the whole string and check if it matches a key. If yes, return that key. Otherwise, repeat the same process with the string minus the last character.
How can I accomplish this task? Different approaches are welcome.
I know a little about the async library and it looks like waterfall is best for what I’m doing. However, it appears that I need to type all the functions from string.length, string.length-1, etc. until the last single character. What I’m looking for is a good replacement for a for loop with a break.
Below I test with an input I assume is always 3 characters or more (because it’s already ugly and more nesting seems pointless for testing). It works, carde resulting in card, and care -> car. Nonsense gives no match.
var http = require("http");
var redis = require("redis");
http.createServer(function(request, response) {
client = redis.createClient();
word = "carde";
client.keys(word, function(err, reply) {
if(err) { response.end(err); client.end(); }
else {
if(reply.length > 0) {
response.end(word);
client.end();
}
else {
client.keys(word.slice(0,-1), function(err, reply) {
if(err) { response.end(err); client.end(); }
else {
if(reply.length > 0) {
response.end(word.slice(0, -1));
client.end();
}
else {
client.keys(word.slice(0, -2), function(err,reply) {
if(err) { response.end(err); client.end(); }
else {
if(reply.length > 0) {
response.end(word.slice(0, -2));
client.end();
}
else {
response.end("no match");
}
}
});
}
}
});
}
}
});
}).listen(8000);
I also tried recursion and it might be the best method. (Thanks to Timonthy Strimple for correcting a mistake).
http.createServer(function(request, response) {
client = redis.createClient();
recursiveKeys("cardinalsin", client, response);
}).listen(8000);
function recursiveKeys(word, client, response) {
if (word.length == 0) {
response.write("0");
response.end();
client.end();
}
else {
client.keys(word, function(err, reply) {
if(err) {
response.write("0");
response.end();
client.end();
}
else {
if(reply.length > 0) {
response.write(word);
response.end();
client.end();
}
else {
return recursiveKeys(word.slice(0,-1), client, response);
}
}
});
}
}
I agree that a recursive solution is probably the best. I approached this problem before studying your code (so as to not affect the experiment) and arrived at a very similar solution. Search for a word with
http://localhost:3000/?word=cardinal