Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a database query (function) which is asynchronous, and as a result I need to use a callback function (no problem with that). However, in Node.js I need to make two separate queries in the same POST function. Both are asynchronous, so I'm having trouble on how to continue with the execution of the POST.

Goal:

  1. Validate form entries for malformations, etc.
  2. Check if username exists in db before saving (must be unique)
  3. Check if email exists in db before saving (must be unique)
  4. Save user if everything checks out, else throw some errors

Normally, I would have something like this (oversimplified):

postSearch = function(req, res, next) {

  var searchCallback = function(err, results) {
    // Do stuff with the results (render page, console log, whatever)
  }
  // This is the db query - async. Passes search results to callback
  defaultSearch(input, searchCallback);
}

Which only has one async query, so only one callback. Normally I would just get the db results and render a page. Now I have to validate some form data, so my POST function looks something like this:

postUser = function(req, res, next) {

  // Some static form validation (works, no issues)

  var usernameExistsCallback = function(err, exists) {
    // Does the username exist? True/false
  }
  // DB query - passes true or false to the callback
  usernameExists(username, usernameExistsCallback);

  var emailExistsCallback = function(err, exists) {
    // Does the email exist? True/false
  }
  // DB query - passes true or false to the callback
  emailExists(email, emailExistsCallback);

  // Check if ALL validation constraints check out, implement error logic
}

The node-postgres module is async, and as a result the queries need callbacks (if I want to return any value, otherwise I can just run the query and disconnect). I have no problem executing both of those queries. I can console.log() the correct results in the callbacks. But now I don't know how to access those results later on in my postUser function.

I've read all about async JavaScript functions, but I've been scratching my head on this one for three hours now trying ridiculous things (like setting global variables [oh my!]) to no avail.

The results I need from these two queries are simply true or false. How can I organize this code to be able to use these results in the postUser function? It seems to me that I need something like a third callback, but I have no clue how to implement something like that. Is it necessary for me to start using async? Would it be a good idea? Nothing in this application is super complex thus far, and I'd like to keep dependencies low <-> it makes sense.

share|improve this question

3 Answers 3

up vote 0 down vote accepted

you can use a common var to keep track of how many responses you got back. if you have them both, you can then do the stuff that needs them in a third "callback", which i called done():

postUser = function(req, res, next) {

  var hops=0, total=2;

   function done(){
       // do stuff with both username and email
   }

  // Some static form validation (works, no issues)

  var usernameExistsCallback = function(err, exists) {
    if(++hops>=total && exists ){ done(); }
    // Does the username exist? True/false
  }
  // DB query - passes true or false to the callback
  usernameExists(username, usernameExistsCallback);

  var emailExistsCallback = function(err, exists) {
    if(++hops>=total && exists){ done(); }
    // Does the email exist? True/false
  }
  // DB query - passes true or false to the callback
  emailExists(email, emailExistsCallback);

  // Check if ALL validation constraints check out, implement error logic
}

you should probably add error handling as needed by your app, specifically in both of the SQL callbacks, but this is a nice parallel IO ajax pattern that should do what you need.

share|improve this answer
    
I'll test it out very shortly! I'm about to go into a meeting, so I'll let you know in a bit how this works out. It looks promising though :) Quick question though - with this kind of logic, would I build errors in the callbacks and pass them to done()? Or would I assume that when done() is called that those two fields are validated (because otherwise I would have rendered some errors already in the original callbacks)? In any case I'll play with it soon and see what works. –  Chris Cirefice Jun 25 '14 at 18:08
    
the advantages to this pattern is that both SQL requests execute at once and it avoids nesting. you can handle errors either way: individually in the "old" callbacks, or by passing errors forward ala done(theErrorOrResponse), and handling everything there. if you already have error handling, it probably easiest to leave them in place. If you need to add error handling, i would pass everything to done(), maybe making done's arguments like many node: callbacks done(err, resp). –  dandavis Jun 25 '14 at 18:11
    
I think that passing the arguments to done() makes the most sense. To me done() implies finished running all validation steps, time to render the page with the results: success or failure! And the results are dependent on whether or not the validation checks out. I think that approach makes more sense, especially because I can build a list of all errors in done() and render the page correctly based on that list. I'll take a look at a real implementation soon, but right now I have to go sign a lease. I'll let you know how this strategy works out :) –  Chris Cirefice Jun 25 '14 at 19:00
    
When I said test it out shortly a few days ago... I suppose that I kind of exaggerated a bit! Well, I've fiddled with your idea, and it works perfectly. I have to say, this is quite smart! I think that I'll likely be using this pattern a lot :) The cool part about it is that instead of passing errors around to a handler function, I can just use req.flash(param, message) in the database callbacks, and those are later accessible in done(). This seems like a really succinct way to do error handling for form validation that requires database lookups. Very very nice, thanks! –  Chris Cirefice Jul 2 '14 at 8:05

How about this:

postUser = function(req, res, next) {
    // Some static form validation (works, no issues)

    var emailExistsCallback = function(err, exists) {
        // Does the email exist? True/false
        var usernameExistsCallback = function(err, exists) {
            // Does the username exist? True/false
            // DO STUFF HERE
        }
        // DB query - passes true or false to the callback
        usernameExists(username, usernameExistsCallback);
    }
    // DB query - passes true or false to the callback
    emailExists(email, emailExistsCallback);

    // Check if ALL validation constraints check out, implement error logic
}
share|improve this answer
    
I thought about doing this, but it would get really confusing I think... I need to put in a bit of error handling, and getting too nested like that is tough (imo). I'll try out both solutions and see what looks/feels best :) –  Chris Cirefice Jun 25 '14 at 18:07
    
you can use promises as well. i don't program too much in node, but i did just finish a project in python/txpostgres, which is async calls. i have some queries that I have to run 8 in a row before the result is known. for those i use deferreds, i don't know if you have those in node? –  Greg Jun 25 '14 at 18:12
    
I believe that promises and deffereds are a thing in Node. I remember reading about them recently, though I didn't particularly see any use for them. With the current spec, nothing in the project will get complicated enough with the queries for those kinds of techniques to be necessary. The most complicated thing I have is running these two queries in POST - most POSTs just run a single one, with the results being straightforward and immediate, so no need for that stuff just yet :P –  Chris Cirefice Jun 25 '14 at 18:58

Simplest way is to nest functions like this:

postUser = function(req, res, next) {
  var emailExistsCallback = function(err, exists) {
    // Does the email exist? True/false

    // Check if ALL validation constraints check out, implement error logic
    next(); // <= you should finally call "next" callback in order to proceed
  }
  var usernameExistsCallback = function(err, exists) {
    // Does the username exist? True/false
    emailExists(email, emailExistsCallback); // <= note this
  }
  usernameExists(username, usernameExistsCallback);
}

Or you can use async, Q, seq or yaff(which is Seq reimplemented). There are number of libs to make your life easier. Better to try them all and decide which one is right for you, your style, requirements and so on.

share|improve this answer
    
I thought about using async, as I could probably run these in parallel with a single callback (not sure about that, don't know much about async). But I wanted to keep the dependencies low, and avoid unnecessary ones if possible. –  Chris Cirefice Jun 25 '14 at 18:09
1  
It's ok. But then, you have to deal with nested callbacks which may become a nightmare at some point. –  mynameisdaniil Jun 25 '14 at 18:14
    
I agree - that's why I thought about using it ;) my most complicated set of callbacks so far is this though. I imagine I'll end up using async in the future, I just didn't want to use it until it was necessary :) –  Chris Cirefice Jun 25 '14 at 18:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.