Express response doesn't work when using mongoose and async - node.js

I'm using express and mongoose. I have a weird issue when I'm using mocha test to run this endpoint.
exports.broadcastMessages = function(req, res, next) {
User.find({}, function(err, users) {
if(err) return next(err);
var push = function(user, callback) {
user.messages.push(req.body.message);
user.save(function(err) {
callback(err);
});
};
var fin = function(err) {
if (err) {
return next(err);
}
console.log('aaaaaaaaaa');
return res.send('ok');
};
async.each(users, push, fin);
});
};
Then I got a timeout error. There is only one user. So it's not a time issue. And I'm sure res.send('ok') was called. But when I removed user.save(). It worked...
exports.broadcastMessages = function(req, res, next) {
User.find({}, function(err, users) {
if(err) return next(err);
var push = function(user, callback) {
user.messages.push(req.body.message);
callback(err);
};
var fin = function(err) {
if (err) {
return next(err);
}
console.log('aaaaaaaaaa');
return res.send('ok');
};
async.each(users, push, fin);
});
};
I don't know why. Why added one more user.save() it doesn't work? res.send is called but no response.
The version of express is 3.4.7. Mongoose is 3.8.2.

When you say "I got a timeout error" do you mean mocha failed your test for taking too long? If so that is probably a problem in your mocha test itself not calling done() correctly. The above code looks OK to me and I think it should work. Some misc points:
Whenever you have this pattern:
user.save(function(err) {
callback(err);
});
You don't need that extra wrapper function that does nothing but call the callback. Just do:
user.save(callback);
Also, looping through the users and saving each one is much less efficient than just having mongodb do them all for you in a single command:
User.update({}, {$push: {messages: req.body.message}}, function (error) {...});

Related

GET request for specific id returning null

I'm attempting to build a simple CRUD application using express and mongodb. My GET request for all database entries is working and my POST request is working but I can't seem to figure out the problem with my GET request for individual entries.
Server.js GET request:
app.get('/api/:id', function (req, res) {
var id = req.params.id;
db.collection('api').findOne({_id: id}, (err, result) => {
if (err){
res.sendStatus(404);
return console.log(err);
}
res.redirect('/');
return console.log(result);
});
});
When I type 'url/api/593555074696601afa192d7f' which is an ID I know exists the console.log is returning null, I'm not sure if I'm doing something wrong?
You should pass ObjectID instance in the query.
let ObjectID = require("mongodb").ObjectID;
app.get('/api/:id', function (req, res) {
var id = req.params.id;
db.collection('api').findOne({_id: ObjectID(id)}, (err, result) => {
if (err){
res.sendStatus(404);
return console.log(err);
}
res.redirect('/');
return console.log(result);
});
});
Give Mongoose a try. It might be of help if your models get complex.

Updating a object in mongoose results in loop

In my nodejs API app I have this route:
router.post('/startuserseries', function(req, res, next){
if(!req.body.username){
return res.status(400).json({message: 'Geen username'});
}
User.findOne({ 'username': req.body.username}, function(err, foundUser){
if(err)
return next(err);
if (foundUser) // check the value returned for undefined
{
foundUser.isdoingchallenges = true;
foundUser.save(function (err) {
if(err) {
console.error('ERROR!');
}
});
}
});
});
When I call this route in postman, the request never ends.
I have tried to use PUT but also didn't work, I tried various structures of code but neither worked.
This request will not finish because it doesn't write a response command on server.
You should solve easily this problem like below:
router.post('/startuserseries', function(req, res, next){
if(!req.body.username){
return res.status(400).json({message: 'Geen username'});
}
User.findOne({ 'username': req.body.username}, function(err, foundUser){
if(err)
return next(err);
if (foundUser) // check the value returned for undefined
{
foundUser.isdoingchallenges = true;
foundUser.save(function (err) {
if(err) {
res.json(err);
}
});
}
res.send(200);
// or your specific result json object
// res.json({"error":false,"message":"completed"})
});
});

Response from node app returns nothing, but should return array

I am testing a nodeJS server, built on the express framework.
When a request is sent to the server, the server should send back some data, in the form of an array. Instead, it is sending back ''.
The test that I am trying to pass is as follows:
it('should send postgres data to the server', function(done) {
request(app)
.post('/chart')
.send({min:"1",max:"100",arrayLength:"12"})
.expect(200, sqlData)
.end(function(err, res){
if(err) {
done(err);
} else {
done();
}
});
});
Note that sqlData is equal to what the sent response should be.
When the router receives a POST request it does the following:
router.post('/', function(req, res) {
res.send(randomSqlTableSelector(req.body.min,req.body.max,req.body.arrayLength));
});
I have checked that req.body.min, max and arrayLength are all the numbers that I would expect them to be.
Thus, the problem is likely in my function randomSqlTableSelector, which, for whatever reason, when called inside of the router, simple returns the empty quotes ''
The function is as follows:
function randomSqlTableSelector(min,max,arrayLength) {
var filledArray = [];
pg.connect(conString, function(err, client, done) {
if(err) {
return console.error('error fetching client from pool', err);
}
client.query('SELECT cell1 FROM random AS retrievedNumber;', function(err, result) {
var psqlData = result.rows;
for (i in psqlData) {
filledArray.push(psqlData[i]["cell1"])
}
return filledArray
});
});
}
You cannot treat functions that perform asynchronous, non-blocking tasks as synchronous and blocking. Try passing in a callback instead:
function randomSqlTableSelector(min, max, arrayLength, cb) {
pg.connect(conString, function(err, client, done) {
if (err)
return cb(err);
client.query('SELECT cell1 FROM random AS retrievedNumber;', function(err, result) {
if (err)
return cb(err);
var psqlData = result.rows,
filledArray = [],
i;
for (i in psqlData)
filledArray.push(psqlData[i]["cell1"])
cb(null, filledArray);
});
});
}
Then use it in your route like:
router.post('/', function(req, res) {
var min = req.body.min,
max = req.body.max,
len = req.body.arrayLength;
randomSqlTableSelector(min, max, len, function(err, array) {
if (err) {
console.log(err);
return res.send(500);
}
res.send(array);
});
});

How to assign query results to an object

I am trying to transfer results data from query function to an object.
console.log(results) line returns 'undefined' result. What should I do?
module.exports = {
show: function(req, res) {
var results;
User.native(function(err, User) {
if(err) {
console.log("There is no exist a User by _id");
}
User.findOne({'_id' : req.param('id')},
function(err, user) {
results = user;
});
});
console.log(results);
return res.view({ stuff : results });
}
};
You have an async issue, the callback from findOne isn't necessarily executed in line with the rest of the code, so you get to the console.log(results) before results = user gets called. You'd want to change it to something like this:
show: function(req, res) {
var results;
User.native(function(err, User) {
if(err) {
console.log("There is no exist a User by _id");
}
User.findOne({'_id' : req.param('id')},
function(err, user) {
results = user;
console.log(results);
// Send response or make a callback here
});
});
}

Custom callback in Express.js get

I have a get in my app.js
app.get('/api/personnel', api.personnel);
that calls this function as a callback to load some data from mongo:
exports.personnel = function(req, res) {
var docs;
db.personnel.find(function(err, docs) {
if (err) {
logError(err);
} else {
res.json({
personnel: docs
});
}
});
};
That works just fine, but I'd really like to be able to call a callback for testing purposes when the function is complete:
exports.personnel = function(req, res, callback) {
var docs;
db.personnel.find(function(err, docs) {
if (err) {
logError(err);
} else {
res.json({
personnel: docs
});
}
callback();
});
callback() is empty when the function is called from the live application and gives me a error:
Error: Can't set headers after they are sent.
How do I go about having a get call my callback?
You can just wrap that function to insert the additional function argument:
exports.personnel = function(req, res, callback) {
var docs;
db.personnel.find(function(err, docs) {
if (err) {
logError(err);
} else {
res.json({
personnel: docs
});
}
});
///////////////////////////////////////////////////
var callback = ...;
pp.get('/api/personnel', function(req, res) {
api.personnel(req, res, callback);
});
third arity in Express is always reserved for next() callback (as found in middlewares).
If you want to have "callback" but does not want to mess up with express, let's hack!
exports.personnel = function(req, res, callback) {
var docs;
db.personnel.find(function(err, docs) {
if (err) {
logError(err);
} else {
res.json({
personnel: docs
});
}
if(process.env.NODE_ENV === 'test')
callback();
});
then, when you want to test, export NODE_ENV=test in your shell

Resources