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
});
});
}
Related
How can I return the count of documents returned by a query?
I have a routing file, which have the following code:
router.post('/facebookLogin', function(req, res, next){
var User=require('../models/user');
var a=User.facebookUserExist(req.body.id, req.body.email);
console.log(a);
res.end();
});
And here is the content of the User model file:
var User=function(data){
this.data=data;
}
User.prototype.data={};
User.prototype.facebookUserExist=function(id, email){
var output;
db.collection('users').find({
$or:[
{
facebookID:id
},
{
email:email
}
]
}).count(function(err, numOfDocs){
output=numOfDocs;
});
return output;
}
module.exports=new User;
I set the value of the output variable in the count method callback, but the function still return undefined.
We know that JavaScript is asynchronous and won't wait for result. So you may either use callback or Promise object, here is example of callback for your code
router.post('/facebookLogin', function(req, res, next){
var User=require('../models/user');
User.facebookUserExist(req.body.id, req.body.email, function(err, count)
if(err)
console.log('Error ', err);
else
console.log(count);
res.end();
});
});
and your User model take a callback as last argument
var User=function(data){
this.data=data;
}
User.prototype.data={};
User.prototype.facebookUserExist=function(id, email, callback){
var output;
db.collection('users').find({
$or:[
{
facebookID:id
},
{
email:email
}
]
}).count(function(err, numOfDocs){
callback(err, numOfDocs);
});
//return output;
}
module.exports=new User;
.count() is required to get total docs in MongoDB. It might help.
USER.find(req.body.id, req.body.email).count(function(err, count) {
console.log("Number of docs: ", count); });
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"})
});
});
I am building a JSON API with ExpressJS, NodeJS and Mongoose:
Input -> id:
app.get('/folder/:id', function (req, res){
return Cars.find({reference: req.params.id}, function (err, product) {
if (!err) {
console.log(product);
return res.send(product);
} else {
return console.log(err);
}
});
});
It shows well the JSON:
[{"_id":"B443U433","date":"2014-08-12","reference":"azerty","file":"087601.png","
....:.
{"_id":"HGF6789","date":"2013-09-11","reference":"azerty","file":"5678.pnf","
...
I just want to display the _id in the JSON, so it is good when I have lots of data.
How I can do that? Something like a filter?
You can chain calls to select and lean to retrieve just the fields you want from the docs you're querying:
app.get('/folder/:id', function (req, res){
return Cars.find({reference: req.params.id}).select('_id').lean().exec(
function (err, product) {
if (!err) {
console.log(product);
return res.send(product);
} else {
return console.log(err);
}
});
});
You would have to iterate over your "products" object to obtain the ids
Something like this:
(Disclaimer: I haven't tested this)
app.get('/folder/:id', function (req, res){
return Cars.find({reference: req.params.id}, function (err, product) {
if (!err) {
console.log(product);
var ids = new Array();
for(var i = 0; i < product.length; i++){
ids.push(product[i]._id);
}
return res.send(JSON.stringify(ids));
} else {
return console.log(err);
}
});
});
--Edit
Also, "products" may already be a JSON string. You may want to parse it before looping.
product = JSON.parse(product);
Other answers are true but I think it's better to limit data in mongoose like this :(it's same as mongo shell commands)
app.get('/folder/:id', function (req, res){
Cars.find({reference: req.params.id} ,{ _id : true } ,function (err, product) {
if (!err) {
console.log(product);
} else {
console.log(err);
}
});
});
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) {...});
I'm trying to show defferent content for logged in and not users on one page.
Here is the code I use for generating / page:
app.get('/',function(req, res){
if (!checkSession(req, res)) {
res.render('index.ejs', {
title: 'FrontSpeak - blog-based social network'
})
} else {
res.render('index.ejs', {
title: 'autrhorized'
})
}
})
checkSession function:
function checkSession(req, res) {
if (req.session.user_id) {
db.collection('users', function (err, collection) {
collection.findOne({
_id: new ObjectID(req.session.user_id)
}, function (err, user) {
if (user) {
req.currentUser = user;
return true;
} else {
return false;
}
});
});
} else {
return false;
}
}
loggin function:
app.post('/', function(req, res){
db.collection("users", function (err, collection) {
collection.findOne({ username: req.body.username }, function (err, doc) {
if (doc && doc.password == req.body.password) {
console.log("user found");
req.session.user_id = doc._id;
}
}
});
});
});
So, it doesn't seems to be working. However, I think this is not the best way to display different content. May be there are some more elegant ways to do this? Thank you!
UPDATE: New login function:
app.post('/', function(req, res){
db.collection("users", function (err, collection) {
collection.findOne({ username: req.body.username }, function (err, doc) {
console.log('found user');
if (doc && doc.password == req.body.password) {
req.session.user_id = doc._id;
res.redirect('/');
};
res.redirect('/');
});
res.redirect('/');
});
});
This is a case of trying to apply the traditional synchronous model to Node's asynchronous callback-driven model.
After your database query completes, you return true, but you're just returning to the database driver. checkSession returned a long time ago. Since that function returns undefined if there is a session.user_id (and false if there isn't), the login check will always evaluate false.
Instead, you can use Brandon's suggestion to make checkSession asynchronous, or I recommend implementing a middleware function:
function checkLogin(req, res, next) {
if (req.session.user_id) {
db.collection('users', function (err, collection) {
if (err) return next(err); // handle errors!
collection.findOne({
_id: new ObjectID(req.session.user_id)
}, function (err, user) {
if (user) {
req.currentUser = user;
} else {
req.currentUser = null;
}
next();
});
});
} else {
req.currentUser = null;
next();
}
}
Now you have two ways of using your middleware function. If you want to check for a user on every request, just add it to the app:
app.use(checkLogin);
Now every single request will have a req.currentUser, but you incur the performance hit of fetching login state from the database for every request. Alternatively, if you only need user information for certain requests, stick the function in the route:
app.get('/', checkLogin, function(req, res) {
if (req.currentUser) {
// logged in
} else {
// not
}
});
You can read more about this in the Express docs.
It looks like you're trying to use checkSession as a synchronous function by checking its return value, but checkSession cannot be synchronous because it depends on asynchronous functionality, namely the callback here: db.collection('users', function (err, collection) .... You'll need to modify checkSession to be async:
function checkSession(req, res, callback) {
if (req.session.user_id) {
db.collection('users', function (err, collection) {
collection.findOne({
_id: new ObjectID(req.session.user_id)
}, function (err, user) {
if (user) {
req.currentUser = user;
callback(true);
} else {
callback(false);
}
});
});
} else {
callback(false);
}
}
and then use it asynchronously in your request handler:
app.get('/',function(req, res){
checkSession(req, res, function(isUser) {
if (!isUser) {
res.render('index.ejs', {
title: 'FrontSpeak - blog-based social network'
})
} else {
res.render('index.ejs', {
title: 'autrhorized'
})
}
});
})