1

I have a question regarding the behaviour of recursive async requests in Node.js.

The function below is intended to return search results from MongoDB. If the initial search results come up empty, I split the text into individual words and then attempt to recursively fetchResult(...) for each word, passing on the res object as a parameter.

function fetchResult(text, res){
    var MongoClient = require('mongodb').MongoClient;

    MongoClient.connect(mongoURL + "/search", function (err, db) {

        if(err) throw err;

        db.collection('results', function(err, collection) {

            // search for match that "begins with" text
            collection.findOne({'text':new RegExp('^' + text, 'i')}, function(err, items){

               var result = (items == null || items.result == null) ? "" : items;

                if (result){
                    res.send(result);
                }
                else {
                    // no result, so fire off individual word queries - if any spaces found
                    if (text.indexOf(' ') > -1){
                        // split string into array
                        var textArray = text.split(" ");

                        // recursively process individual words
                        for (index = 0; index < textArray.length; index++) {
                            // ***** RACE CONDITION HERE? *****
                            fetchResult(textArray[index], res);
                        }
                    }
                    else {
                        // just return empty result
                        res.send(result);
                    }
                }
            });
        });
    });
}

I suspected this might cause a bit of a race condition, as the reference to res fans out asynchronously, and this was confirmed when I ran the code and observed the following error:

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)

So my question is: How can I achieve the desired recursive behaviour of executing individual string queries in sequence, returning only when we find the first result (or at the end of the process when search returned no results at all)?

1
  • study about the promises Commented Mar 20, 2017 at 12:37

1 Answer 1

1

Your code needs some refactoring.

Firstly, remove the MongoClient.connect call from the fetchResult function. You can connect once and store the db object for later use.

Secondly, with your approach you are returning a response for each word in the query. I don't think a recursive call is the way to go here.

You will have multiple async queries if your first query fails, and you somehow need to aggregate the results...this is where it gets tricky. I am not so familiar with Mongo, but I believe you can avoid this by retrieving a set of results with find $in. See this question, maybe it helps.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, I've separated the creation of the connection and collection so it's reusable now. At which point now do I close the connection though?
I don't have the whole picture of your code, but I suppose your fetchResult method is called from a request method...you could manage your connection there.
So what is the actual benefit of moving the connection creation code to the calling method?
cleaner code...perhaps you need it to make another query, besides fetchResult...like the user or something.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.