krakig
krakig

Reputation: 1555

node.js database queries in order

I'd like to perform queries in order but I don't know what is the best approach.

Let's say I'd like to do the following :

if (name) {
  //first query
  db.query({name:name}).exec(function(err,result) {
  //save result
  })
}
if (isEmpty(result)) {
  //make another query
  db.query({anotherField:value}).exec(function(err,result) {
  //save result
  })
}

Should I use promises on that case?

That would be an example with cakePHP :

if (!isset($field1)) {
  $result = $this->item->find( ... conditions => ... = $field2);
} else {
  if (!isset($field2)) {
    $result = $this->item->find( ... conditions => ... = $field1);
  } else {
    $result = $this->item->find( ... conditions => ... = $field1 && ... =$field2);
    if (empty($result)) {
      $result = $this->item->find( ... conditions => ... =$field2);
    }
  }  
}

Upvotes: 2

Views: 790

Answers (2)

Plato
Plato

Reputation: 11052

If you mean "in order" you can nest the callbacks. Passing callbacks is the classic (non-promise) way to structure asynchronous code:

function doMultipleAsyncThings(name, callback){
  if (name) {
    //first query
    db.query({name:name}).exec(function(err,result) {
      if (isEmpty(result)) {
        //make another query
        db.query({anotherField:value}).exec(function(err,result) {
          //save result
        })
      } else {
        //save result
      }
    })
  } else {
    return callback('no name');
  }
}

Heads up, after more than 2 or so operations, you end up in 'callback hell' with 100+ lines of nested code, the async library is helpful for this:

var async = require('async');
doMultipleAsyncThings('plato', function(){
  console.log(arguments)
});

function doMultipleAsyncThings(name, callback){
  // `callback` is a passed-in function to call after doMultipleAsyncThings is done
  // Here, it is the function we passed in above after 'plato'
  async.waterfall([function(done){
      done(null, name);
    },
    firstQuery,
    secondQuery,
  ], callback)
}

function firstQuery(name, done){
  if (name) {
    // You can define and pass a callback inline:
    db.query({name:name}).exec(function(err,result) {
      done(err, result);
    })
  } else {
    done('no name');
  }
}

function secondQuery(result, done){
  if (isEmpty(result)) {
    // You can pass a callback by reference:
    db.query({anotherField:value}).exec(done)
  } else {
    //save result
    done();
  }
}

Upvotes: 2

Mikey
Mikey

Reputation: 2951

Promises would be a good fit for this, the q library is the most common for this. You probably just want to nest your promises like so:

var q = require('q');

if (name) {
  //first query
  q.ninvoke(db.query({name:name}), 'exec')
  .then(function(result) {
    //save result
    if (isEmpty(result)) {
      //make another query
      q.ninvoke(db.query({anotherField:value}), 'exec')
      .then(function(result) {
        //save result
      })
      .fail(function(err) {
        //handle failure
        console.error(err, err.stack);
      });
    }
  })
  .fail(function(err) {
    //handle failure
    console.error(err, err.stack);
  });
}

q.ninvoke allows us to convert standard nodejs functions into their promise equivalent.

Upvotes: 2

Related Questions