Reputation: 326
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
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
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