mjoyce91
mjoyce91

Reputation: 326

Making Synchronous MongoJS Queries in NodeJS

I use the MongoJS driver to run queries in my Nodejs server. I have two queries that I would like to run in order, but the asynchronous nature of javascript leaves me with unexpected results when I make a request. Here's what I have:

app.post('/teams', isLoggedIn, function (req, res){

    db.collection.update({"_id":mongojs.ObjectId(req.body.x)},{$pull:{"teams":{"_id":req.body.y}}},
    function (err, docs) {
    console.log(docs); res.json(docs);
    });

    db.collection.update({"_id":mongojs.ObjectId(req.body.x)},{$push:{"teams":{"_id":req.body.y,"team":req.body.z, "member":true}}},
    function (err, docs) {
    console.log(docs); res.json(docs);
    });

});

I need these queries to run in order ($pull and THEN $push). I've tried running the second query within the function(err, docs){...} of the first query, but even when I pass req or variablized versions of req, it returns as undefined. What's the best way to go about getting these queries to run in order?

Update: Here's what I ended up doing using async (Thanks for the tip, Satisfaction) based on this tutorial. Something I should have mentioned was that this query exists within a loop, which I did not include in my example request above.

async.parallel([
       function(callback) { //This is the first task, and callback is its callback task
          console.log('first1 '+x+'pulled');
          db.collection.update({"_id":mongojs.ObjectId(req.body.x)},{$pull:{"teams":{"_id":req.body.y}}}, function(err, docs) {
          //Now we have saved to the DB, so let's tell async that this task is done
          res.json(docs);
          callback();
        });
       },
       function(callback) { //This is the second task, and callback is its callback task
          console.log('second1 '+x+'pushed');
          db.collection.update({"_id":mongojs.ObjectId(req.body.x)},{$push:{"teams":{"_id":req.body.y,"team":req.body.z, "member":true}}}, callback); //Since we don't do anything interesting in db.save()'s callback, we might as well just pass in the task callback 
          }
          ], function(err, docs) { //This is the final callback
          res.json(docs);
          console.log('Both a and b are saved now');
});

Update 2: Maybe I spoke too soon. Queries are still not completing as expected about 5% of the time.

Upvotes: 0

Views: 503

Answers (2)

Rahul Kamboj
Rahul Kamboj

Reputation: 469

var Q = require("q");

app.post('/teams', isLoggedIn, function (req, res){

firstFunction(req,res).then(function(result){
    var resultFromFirst = result
    db.collection.update({"_id":mongojs.ObjectId(req.body.x)},{$push:        {"teams":{"_id":req.body.y,"team":req.body.z, "member":true}}},
        function (err, docs) {
            console.log(docs); res.json(docs);
        });

})


});

var firstFunction = function (req,res) {
console.log("first function")
var d1 = Q.defer();
  db.collection.update({"_id":mongojs.ObjectId(req.body.x)},{$pull:    {"teams":{"_id":req.body.y}}},
    function (err, docs) {
        console.log(docs); res.json(docs);
        d1.resolve(docs);
    });


return d1.promise;
}

Before Run:

npm install q -g

use sudo if any issue in package installation

Upvotes: 1

Andrius
Andrius

Reputation: 5939

As you mentioned yourself, NodeJS works asynchronously.

To get stuff done in sync, you'll need to use a library, like, async or use promises.

Just a quick example how you could do things work using async's "auto" (I like using it as I have much more control over the simplistic "waterfall" method):

async.auto({
    pull: function(callback){
        db.collection.update({"_id":mongojs.ObjectId(req.body.x)},{$pull:{"teams":{"_id":req.body.y}}},callback);
    },
    push: ['pull', function(callback, results){
        db.collection.update({"_id":mongojs.ObjectId(req.body.x)},{$push:{"teams":{"_id":req.body.y,"team":req.body.z, "member":true}}},callback);
    }]
}, function(err, results) {
    if(err) {
        console.log(err);
    }
    console.log(results.pull);
    console.log(results.push);
});

I have not tested the code, feel free to look it all up yourself here.

Upvotes: 2

Related Questions