Return document count with mongoose in NodeJS - node.js

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); });

Related

Express js use values from mongodb to outside of the query

I am new with express js and node js. I am wonder if its possible to do this or not.
1st thing I'm trying to get the count on 1 query.
2nd I query collection login. loop it and format and get the name values using ids.
I get undefined on count1 and I see it ommitted on the json response.
how do I pass the query returns outside of the query?
router.post('/logmein', function(req, res, next) {
var email = req.param('email');
var password = req.param('password');
var count1;
MongoClient.connect(MongoUrl, function(err, db) {
if (err) return;
db.collection('users').count({email: email,password: md5(password)}, function(err, count) {
count1 = count;
});
db.collection('login').find({email: email,password: md5(password)}).toArray(function(err, results){
console.log(results); // output all records
});
//use results
/*
foreach each results format with other info
var new_array;
*/
res.json({"success": true,"count":count1,new_array: new_array});
});
});
Async issues, you have to look more at it. Use the async module and then you will be able to fire the queries in parallel. Finally, you will have the results in the final callback. This snippet will fix your issue:
var async = require('async');
router.post('/logmein', function (req, res, next) {
var email = req.param('email');
var password = req.param('password');
var retResults;
var count1;
MongoClient.connect(MongoUrl, function (err, db) {
if (err) return;
async.parallel([
function(callback){
db.collection('users').count({ email: email, password: md5(password) }, function (err, count) {
return callback(err, count);
});
},
function(callback){
db.collection('login').find({ email: email, password: md5(password) }).toArray(function (err, results) {
return callback(err, results);
});
}
], function(err, results) {
if (err) {
// #todo: handle the error
}
count1 = results[0];
retResults = results[1];
//use results
/*
foreach each results format with other info
var new_array;
*/
res.json({ "success": true, "count": count1, new_array: new_array });
};
});
});
You need something like async.parallel to control the async flow of your nodejs application
async.parallel([
function(callback){ ... },
function(callback){ ... }
], function(err, results) {
// optional callback
};

NodeJS / Mongoose Filter JSON

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);
}
});
});

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
});
});
}

Unit testing using sequelize, mocha and async : Sequelize doesn't call back

I have a problem with mocha and async/sequelize I think.
I have a form that allow the user to enter his pseudo and password and do some asynchronous work with that. It works really fine. But I want to write unit testing for all my application.
When I wrote the test for this part, it doesn't work, because sequelize never call the success function back and I really don't know why, because it works without mocha.
Here is the code for the processing of the form :
var inscrire = function(data, cb){
//Getting the data
var pseudo = data.pseudonyme;
var password = data.password;
var passConfirm = data.passwordConfirmation;
//Verifying the form
//Pseudonyme
if(pseudo.length < 1 || password.length > 255){
cb(null, 'form');
return;
}
//Password
if(password.length < 1 || password.length > 255){
cb(null, 'form');
return;
}
//Password confirmation
if(passConfirm != password){
cb(null, 'form');
return;
}
async.waterfall([
//Finding the user
function(callback){
//Find the user with the pseudonyme
db.User.find({where : {'pseudonyme' : pseudo}}).done(function(err, user){
console.log('AAAA');
if(err){
throw err;
}
console.log('YEAH');
callback(null, user);
});
},
//Creating the user if he's not here
function(user, callback){
//If the user is not in the base
if(!user){
//Hash the password
password = hash(password);
//Create the user
db.User.create({'pseudonyme' : pseudo,
'password' : password}).success(function(){
callback(null, true);
});
}else{
//The user is alreadyhere
callback(null, 'useralreadyhere');
}
}
], function(err, result){
//Throw any exception
if(err){
throw err;
}
//Returning the result
cb(null, result);
});
}
And here is the part of my unit test:
describe('#user-not-in-db', function() {
it('should succeed', function(){
var data = {
'pseudonyme' : 'test',
'password' : 'test',
'passwordConfirmation' : 'test'
};
async.waterfall([
function(callback){
index.inscrire(data, callback);
}
], function(err, result){
console.log('YO');
result.should.equal('YOO');
});
});
});
Thank you in advance.
I see at least one problem with the unit test as you have written it:
It's running as a synchronous test.
To run an async tests in mocha, the it test callback must take a "done" argument or return a promise. For example:
describe('foo', function(){
it('must do asyc op', function(done){
async.waterfall([
function(cb){ setTimeout(cb,500); },
function(cb){ cb(null, 'ok'); }
], function(err, res){
assert(res);
done();
}
);
});
});
See part of the mocha documentation for more examples:
http://visionmedia.github.io/mocha/#asynchronous-code

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