Multiple connection error when using node js and mongodb - javascript

I'm using the following schema located in my /routes/schema.js file...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
username: String,
password: String,
name: String,
last: String,
year: Number,
degree: String
});
var User = mongoose.model('User', userSchema);
module.exports = {
User: User
}
In my /routes/register.js file I am storing some information using POST data...
var User = require('../routes/schema').User;
exports.postRegister = function (req, res) {
var u = new User({
username: req.body.reg_username,
password: req.body.reg_password,
name: req.body.reg_name,
last: req.body.reg_lastname,
year: req.body.reg_year,
degree: req.body.reg_degree
});
u.save(function (err) {
if (err) {
throw err;
}
else {
console.log("saved");
res.render('index', { title: 'Express' });
}
});
}
Everything gets saved fine in my Database. But now, this register.js file redirects the user back to /routes/index.js where the user must then sign in using some credentials stored in the database.
So in my index.js file I need to check if username and password exist together in a collection in my database, I tried the following...
var User = require('../routes/schema').User;
exports.signin = function (req, res) {
User.findOne({
username: req.body.log_username,
password: req.body.log_password
}, function (err, docs) {
if (docs.length) {
console.log("name exists");
}
else {
console.log("no exist");
}
});
};
I used the findOne function with the same Schema to check if username and password exist in a collection in the database, but it doesn't work properly. I seem to get a multiple connection error and I do not know how to avoid it.
When I try to login using some credentials already in the database, the console prints out no exist meaning the else statement in exports.signin is reached.

The value of the docs will be null if the object is not found in the collection.
If the user enters wrong credentials, you will be calling docs.length on null object, which will cause an error. Use docs != null instead, to avoid calling length on null object.

try it docs.length !== 0 this is check docs field is existed or empty.

Related

Mongoose findOne() callback returning null

I'm trying to find a user in my node app with mongoose by using
var User = require('../app/models/user');
function mongoTest() {
var publicAddress = "0x8a6be8979340faa30020b0c1f617d8fd4309679f";
User.findOne({"publicAddress": publicAddress}, (err, user) => {
if (err) {
res.status(500).send(err)
} else {
console.log(user);
}
});
}
and err and user always return null. From other questions here (this and this), this usually seems to be related to mongoose pluralising collections. However, I don't think that's my issue because my users.js has
module.exports = mongoose.model('User', userSchema);
// Have also tried module.exports = mongoose.model('User', userSchema, 'User');
For completeness, users.js is
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
// Define the schema for our user model
var userSchema = mongoose.Schema({
local: {
username: String,
password: String,
pictureCaption: String,
publicAddress: String,
contractAddress: String
}
});
Finally, I'm sure that public address exists because I can see it in the mongoDB with Robo 3T.
In your userSchema the publicAddress is part of local object.
var userSchema = mongoose.Schema({
local: {
username: String,
password: String,
pictureCaption: String,
publicAddress: String,
contractAddress: String
}
});
You are trying to find an object with publicAddress but it's actually inside the local object. So you should edit the query as follows to get the result.
User.findOne({"local.publicAddress": publicAddress}, (err, user) => {
if (err) {
res.status(500).send(err)
} else {
console.log(user);
}
});

How to do unit test in dependent modules (node.js)?

I have an application with two modules (Book and User). The book model looks like this:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var BookModel = new Schema({
name: String,
author: String,
description: String,
_user: {type: Schema.Types.ObjectId, ref: 'User'}
});
module.exports = mongoose.model('Book', bookModel);
And the user model:
var mongoose = require('mongoose'),
bcrypt = require('bcryptjs'),
Schema = mongoose.Schema;
var userModel = new Schema({
name: String,
username: String,
password: String,
});
module.exports = mongoose.model('User', userModel);
I want to do a unit test in the POST method (inserting a book in the DB) with the condition of not allowing empty name. This is what I have in the POST method:
var post = function (req, res) {
var bookNew = new book(req.body);
// get paylod from the user's token
var payload = tokenManager.getPayload(req.headers);
if (req.body._user)
delete req.body._user;
if (!req.body.name) {
res.status(400);
res.send("Name is required");
} else if (payload == null || payload == undefined) {
res.status(400);
res.send("Token error");
} else {
// store the user id
bookNew.set('_user', payload.id);
bookNew.save();
res.status(201);
res.send("Book saved");
}
};
As you can see, I get the payload from the token (created when the user is logged in). I do this because the payload contains the user id and, then, I insert it in _user (property in book model).
The problem is that if I do a unit test in order to verify if the book’s property (name) is filled, I don’t have a user to retrieve the payload. Therefore, the payload will be undefined and the book unit test will not be successful in any case. Do you have any suggestion on what I should do? It looks like I have to create a user in order to test all book modules… but I am not sure if that is the most suitable solution.

Express/Mongoose REST trouble

Im running Express on my application with a delete route below:
router.route('/lists/:id')
.delete(function(req, res){
Entry.remove({
_id: req.params.id
}, function(err, list){
if(err)
res.send(err)
list.title = req.body.title;
res.json({message: 'successfully deleted'});
console.log('DELETE on /lists/'+ req.params.id);
});
});
Here is my Mongoose schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ListSchema = new Schema({
title: String
});
module.exports = mongoose.model('List', ListSchema);
When my application hits the delete route, my terminal logs the appropriate statement, but the model is not deleted from the database. When I call fetch on the collection, all of there records are still there.
I am using a very similar approach on a different collection of data on my website, and it works fine, so Im really at a loss for why this is happening.
Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema constructor. The type assiged is an ObjectId to coincide with MongoDBs default behavior
Try passing the _id as ObjectId:
var ObjectId = require('mongoose').Types.ObjectId;
var query = { _id: new ObjectId(req.params.id) };

How to set run multiple controller functions in nodejs

I am currently working on boiler plate code of mean.io and implementing passwordresetemail to it. When ever user asks for password reset with email as parameter, I create a salt(resetid) and send him an email having that salt as reset link.
I have user's email in the req but want to append other information of the user(user._id) before it enters into actual createemail controller function. I want following function(userbyemail) to be run before it goes into createResetPasswordEmailLink
/**
* Find user by email
*/
exports.userByEmail = function(req, res, next, email) {
User
.findOne({
email: email
})
.exec(function(err, user) {
if (err) return next(err);
if (!user) return next(new Error('Failed to load User with email ' + email));
req.user = user;
next();
});
};
exports.createResetPasswordEmailLink = function(req, res) {
var resetPassword = new ResetPassword(req.body);
resetPassword.resetId = new User().makeSalt();
**resetPassword.user = req.user._id; // currently req.user is null**
console.log(resetPassword.userId);
resetPassword.save(function(err) {
if (err) {
// handle error
}
res.status(200);
return res.redirect('/');
});
};
Following is my resetPassword schema
var ResetPasswordSchema = new Schema({
created: {
type: Date,
default: Date.now
},
resetId: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
My routes is defined as follows
// Setting up the users resetpasswordlink
app.route('/createresetpasswordemaillink')
.post(users.createResetPasswordEmailLink);
I could solve this issue with app.params. App.params is exactly defined for this kind of usage.
I added
// Setting up the userId param
app.param('email', users.userByEmail);
to my routes and it automatically executed this function before the req is passed on to regular controllers.
From the documentation, App.param is defined as
app.param([name], callback)
Map logic to route parameters. For example when :user is present in a route path you may map user loading logic to automatically provide req.user to the route, or perform validations on the parameter input.

How to Post and Get Data Unique to Each Logged In User with Express and Mongoose?

I am currently working on a small single page app that lets users login with PassportJs and Mongoose.
One of the things I am trying to do is allow users to login and each user has a unique todo/task list which are items associated to that user.
I have been able to do the first part...users can login and express/passport session is accessed using jade #{user.username}, so when logged in the user see "Welcome, [user.username]".
Now I add a form (accessible when user logged in) and the form says undefined. I'm not sure if its my Mongoose schema design or Routes that are causing the problem. Thanks for reading this and here is my code:
Mongoose Schema
mongoose.connect('mongodb://localhost/poplivecore')
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var user = new Schema({
username: String,
password: String,
email: String,
todos: [Todo]
});
var Todo = new Schema({
name: {type: String, default : ''},
user: {type: Schema.ObjectId, ref: 'user'},
createdAt : {type : Date, default : Date.now}
})
var Todo = mongoose.model('Todo', Todo);
var user = mongoose.model('user', user);
Here are my Express routes:
//WORKING....This route is the one that a logged in user sees, form posts with
app.get('/home', ensureAuthenticated ,function(req, res){
res.render('home', { user: req.user});
});
//WORKING...This route allows user to post/submit the login
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }),
function(req, res) {
res.redirect('/home');
});
//WORKING....This route allows user to create a user/account
app.post('/create', function(req, res, next){
var user = new user({
"username": req.body.username,
"password" : req.body.password,
"email" : req.body.email});
user.save(function (err) {
if (!err) {
res.redirect('/home');
}
else {
res.redirect('/');
}
});
});
**//NOT WORKING..Post used in the form inside the logged in Area, that adds a 'todo'**
app.post('/todo', function(req, res){
var todo = new todo(req.body.name);
todo.save(function (err) {
if (!err) {
res.redirect('/home');
}
else {
res.redirect('/fail');
}
});
});
Jade Form, for Adding a todo
enter code here
form(method='post', action='/todo')
//input(type='hidden', value= user._id)#userId
fieldset
label Todo
div.input
input(name='todo.name', type='todo.name', class='xlarge')
div.actions
input(type='submit', value='Save', class='btn primary')
button(type='reset', class='btn') Cancel
I can post on github if you need to see more code...thanks.
Update as per 'numbers1311407' suggesion
*New post route for todo, also changed todo to 'Todo' in both schema and routes*
app.post('/todo', function(req, res){
var todo = new Todo({name : req.body["Todo.name"]});
todo.save(function (err) {
if (!err) {
res.redirect('/home');
}
else {
res.redirect('/fail');
}
});
});
There are at least two problems here that would cause this to not work:
The name of the input passed by your form is todo.name, and you're referencing it as req.body.name in the route.
mongoose models are instantiated with an attributes object, but you're just giving it a string (which, actually, is null currently because of the first issue).
So for your route to work it would look more like this:
app.post("/todo", function (req, res) {
var todo = new Todo({name: req.body["todo.name"]});
todo.user = req.user._id;
// ...
});
If you wanted to pass todo attributes as a parameter object, you'd want to name them with brackets todo[name], rather than dots. This would result in the todo attributes being on object on the req.body, e.g.:
app.post("/todo", function (req, res) {
console.log(req.body.todo); //=> { name: "whatever" }
// ... which means you could do
var todo = new Todo(req.body.todo);
todo.user = req.user._id;
// ...
});
Some other things you might want to change:
As #NilsH points out, you don't want to pass the user id in the form, as that would allow anyone to make a todo for anyone else just by knowing their ID. Rather since you're using passport, make use of the user in the session. You should have access to the user ID through the passport determined user, like req.user._id. I added this to both examples above.
The type of your form input is todo.name. It should be text (that's what the browser is treating it as anyway).
Not necessarily an error, but model names are conventionally capitalized. This also solves an issue your code has above in that you're redefining todo when you say var todo = new todo(...).

Categories