Cannot read property of undefined error in mongoose method - node.js

I am using node for requesting data using tokens for authentication but getting an error
Error 500 : Cannot read property of undefined
Here is my code
Function findByToken()
var User = this;
var decoded;
try {
jwt.verify(token, 'abc');
} catch(e) {
return Promise.reject();
}
return User.findOne({
'_id': decoded._id,
'tokens.token': token,
'tokens.access': 'auth'
});
This function takes token as an argument and find the data into database.
Route
app.get('/users/me', (req,res) => {
var token = req.header('x-auth');
User.findByToken(token).then((user) => {
res.send(req.user);
}).catch((e) => {
res.send(e);
});
});
This is the route where i am using my function to return the data. But getting a 500 error please help me with this.

You should use statics methods
For example:
animalSchema.statics.findByName = function(name, cb) {
return this.find({ name: new RegExp(name, 'i') }, cb);
};

Related

Cast to ObjectId failed for value ... at path "_id" for model but I am not doing any query

I have an express route that gets call with axios from the frontend. The thing is, not matter what I put into the route I always get the same error:
"Cast to ObjectId failed for value "getTodosMisProductos" at path "_id" for model "local""
I'm not doing any query to mongoose in that route but in any other route where I make a query everything works fine.
I've checked the middleware but there is not any query to mongoose
getTodosMisProductos
router.get("/getTodosMisProductos", auth, async (req, res) => {
/*
try {
const data = await Local.findOne({ user: req.user.id }).populate("products.producto");
console.log(data);
if (!data) {
return res
.status(404)
.json({ errors: [{ msg: "No se encontro el local" }] });
}
return res.status(200).json(data.products);
} catch (error) {
console.log(req.user.id);
console.error("error en llamado");
return res.status(500).send("Server Error");
}
*/
console.log("algo");
return res.status(200).json({ msg: "success" });
});
the code commented is the code I need to use, I changed it for testing purposes but even with that simple new code I get the same error.
auth middleware
const jwt = require("jsonwebtoken");
const config = require("config");
module.exports = function (req, res, next) {
// Get token from header
const token = req.header("x-auth-token");
// Check if not token
if (!token) {
return res
.status(401)
.json({ msg: "No tienes autorización para hacer esto" });
}
// Verify token
try {
const decoded = jwt.verify(token, require("../config/keys").jwtSecret);
req.user = decoded.user;
next();
} catch (error) {
res.status(401).json({ msg: "El token es inválido" });
}
};
action from where the route gets called
export const getAllProductos = () => async (dispatch) => {
try {
console.log("Esto se llama");
const res = await axios.get("/api/local/getTodosMisProductos/");
dispatch({
type: SET_PRODUCTS,
payload: res.data,
});
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, "danger")));
}
}
};
The response status is always 500 (Internal Server Error)
EDIT
//#route GET api/local/:id
//#desc obtener local por id
//#access private
router.get("/:id", auth, async (req, res) => {
try {
const local = await Local.findById(req.params.id);
if (!local) {
return res
.status(404)
.json({ errors: [{ msg: "No se encontro el local" }] });
}
return res.status(200).json(local);
} catch (error) {
console.error(error.message);
res.status(500).send("Server Error");
}
});
You have another route that also match /api/local/getTodosMisProductos/
Apparently it got matched with /api/local/:id,
where you get req.params.id = "getTodosMisProductos" and got passed down to await Local.findById(req.params.id)
And mongoose can't convert "getTodosMisProductos" to ObjectId, hence the error.
The order in which you declare the route affects the matching priority.
The order is first comes first serves, so make sure you declare /api/local/addProducto or any other routes that starts with /api/local/ before declaring /api/local/:id

Using node.js 'util' to promisify is returning an error

I'm trying to create a function in a file to return a promis, which I will call form another file. I'm trying to use the 'util.promisify' to wrap the function, but I'm getting an error. Here is the code and the error:
from my 'checkEmail.js':
const Profile = require('../../models/profile');
const util = require('util');
var exports = module.exports = {};
exports.findEmail = util.promisify(checkEmail());
function checkEmail (email) {
Profile.findOne({ 'emails': { $elemMatch: { email_address: email } } }, (err, userEmail) => {
let conclusion = false;
if (err) {
console.log('Error in looking up an existing email');
} else {
if (userEmail) {
console.log('We found an existing owner for email: ' + email);
conclusion = true;
}
}
return conclusion;
})
}
Calling it on 'profile.js':
router.route('/addemail/:id')
// ADD EMAILS
.put(function (req, res) {
Profile.findOne({ 'owner_id': req.params.id }, function (err, profile) {
if (err)
res.send(err);
EmailCheck.findEmail(req.body.email_address).then((data)=>{
console.log('The answer is: ', data);
});
profile.emails.push({
email_type: req.body.email_type,
email_address: req.body.email_address
})
profile.save(function (err) {
if (err)
res.send(err);
res.json(profile);
});
});
});
The error I'm getting is:
Config for: http://localhost:3000
internal/util.js:272
throw new ERR_INVALID_ARG_TYPE('original', 'Function', original);
Any help would be appreciated.
In order to promisify the function that you pass to util.promisify must:
Take a function following the common error-first callback style, i.e.
taking a (err, value) => callback as the last argument, and returns a version that returns promise
So you can either promisify Profile.findOne, or pass a callback as the last argument to checkEmail
function checkEmail (email, callback) {
Profile.findOne({ 'emails': { $elemMatch: { email_address: email } } }, (err, userEmail) => {
let conclusion = false;
if (err)
return callback(new Error('Error in looking up an existing email'));
if (userEmail) {
console.log('We found an existing owner for email: ' + email);
conclusion = true;
}
return callback(null, conclusion);
})
}
And then you should call it like this:
exports.findEmail = util.promisify(checkEmail);
Otherwise you're passing to .promisify the returned value of checkEmail which is not a function following the style commented above.
You have typo, use util.promisify(checkEmail) instead, parentheses are redundant

Can i call a function from inside mustache templates which takes parameters?

I have a function defined in user_helper.js which generally returns value.
When I call getUserInfo() (in user_helper.js) from mustache template, it normally returns a String. But when I want results from mongoose query it returns NULL and not even shows any error.
index.js
router.get("/home", (req, res) => {
Profile.find()
.then(profile => {
res.render("index", {
userID: req.session.userID,
helper: require("../helpers/user_helper")
});
})
.catch(err => {
res.status(400).send("Unable to fatch");
});
});
module.exports = router;
user_helpert.js
var users = {
getUserInfo: function() {
return function(userID, render) {
var query = {_id:userID};
User.findOne(query, function(error, user) {
// Inside, return nothing
if (error) {
return error;
} else {
return user;
}
});
return "Some Text"; //This one's return result
};
}
};
module.exports = users;
mustache template
{{#helper.userInfo}}{{ userID }}{{/helper.userInfo}}
It should returns user information from database.
Can anyone knows about this or any better approach ?
There are many issues in your function.
The first one is that the query variable does not exist in the getUserInfo function. So the User.findOne() can't be executed.
The second error is that the User.findOne() method is asynchronous, so you won't be able to return a value as expected.
You should modify your /home route in the index.js to retrieve the user:
router.get("/home", (req, res) => {
User.findOneById(req.session.userID)
.then(user => {
res.render("index", {
user: user
});
})
.catch(err => {
res.status(400).send("Unable to fetch");
});
});
And in your template:
{{user.id}}

how to resolve data and hash error in node js bcrypt

Error: data and hash arguments required
i am doing simple, login signup and forgot password in node js using
bcrypt hash
code : for login
app.post('/login', (req, res) => {
console.log('login');
let {email, password} = req.body;
User.updateOne({email: email}, ' email password', (err, userData) => {
if (!err) {
let passwordCheck = bcrypt.compareSync(password, userData.password);
if (passwordCheck) {
console.log('login2');
req.session.user = {
email: userData.email,
id: userData._id
};
req.session.user.expires = new Date(Date.now() + 3 * 24 * 3600 * 1000);
res.status(200).send('You are logged in, Welcome!');
} else {
res.status(401).send('incorrect password');
console.log('login3');
}
} else {
res.status(401).send('invalid login credentials');
console.log('login4');
}
});
});
code for signUp :
app.post('/signup', (req, res) => {
let {email, password} = req.body;
let userData = {password: bcrypt.hashSync(password, 5, null), email };
console.log('out save');
let newUser = new User(userData);
newUser.save().then(error => {
if (!error) {
console.log('in save');
return res.status(200).json('signup successful');
} else {
if (error.code === 11000) {
return res.status(409).send('user already exist!');
} else {
console.log(JSON.stringigy(error, null, 2));
return res.status(500).send('error signing up user');
}
}
});
});
i have tried console logging few lines and turned out that the code doesn't go into signup
newUser.save();
tell me where i'm going wrong
The issue is with this line newUser.save().then(error => {. Do you notice the .then(). That is a resolved promise so it wouldn't be returning an error. Typically you would see something like this.
Promise()
.then((result) => {
// result is a resolved promise
})
.catch((error) => {
// error is a rejected promise
})
So you should try changing your code to this:
newUser.save()
.then(result => {
console.log('in save')
return res.status(200).json('signup successful')
})
.catch(error => {
if (error.code === 11000) {
return res.status(409).send('user already exist!')
} else {
console.log(JSON.stringigy(error, null, 2))
return res.status(500).send('error signing up user')
}
})
It looks like you're using mongoose, here is the API docs for Document.prototype.save() https://mongoosejs.com/docs/api.html#document_Document-save
Their documentation uses callback functions for the most part but if you scroll to the end of the .save() documentation you will see they show one example with a promise.
bcrypt.compareSync takes 2 parameters; passwordToCheck, passwordHash
You are getting error "bcrypt Error: data and hash arguments required"
This error means one or both parameters are either null or undefined,
In your case you need to make sure that password, userData.password are correctly going in function bcrypt.compareSync

Node.js. mongodb return promise

I am creating REST api and want to authenticate user by token. I've found tutorial and wrote function based on it. But it's on callbacks and I want to return Promise from mongoose model and in route use then rather than do callbacks. Here is my function:
UserSchema.statics.authenticate = function(login, password, fn) {
var token;
this.findOne({login: login}, function(err, user) {
var _token;
if (err)
token = ( false);
if (!user){
token = ( false);
}
else if (user)
{
if (user.password != password)
token = ( false);
else
{
token = jwt.sign(user, secret);
user.update(
{ $set: {
token: token ,
lastActive: new Date()
}}
);
}
}
fn(token);
});
};
module.exports = mongoose.model('User', UserSchema);
I know that to return promise from find function i have to usee exec() but what I want to achive is to return token do I have to var q = new Promise in function and return this q object?
This is my route
router.post('/authenticate', function(req, res, next) {
User.authenticate( req.body.login,req.body.password, function(response){
if(response)
res.status(200)
.send({'success': true, token: response, msg: "Successfuly authenticated"});
else
res.status(200)
.send({'success': false, token: null, msg: "Wrong username or password"});
})
});
Bluebird is a great library to handle this.
You can define a promise before a query, resolve it in the response, and yield it after.
For example:
var Promise = require('bluebird');
var defer = Promise.defer();
collection.find({name: 'name here'}).exec(function(err, result) {
if(err){
defer.reject(err);
} else {
defer.resolve(result);
}
});
return defer.promise
The best way to use mongoose with promises is to used the bluebird npm package :
npm install --save bluebird
and to make that on your models declaration :
const Promise = require('bluebird');
//...
let Model = mongoose.model('User', UserSchema);
module.exports = Promise.promisifyAll(Model);
Now you can use all mongoose methods with promises :
const User = require('./User');
User.find().then((users) => {
if (users) {
reply(null, users);
return;
}
reply(null, []);
}).catch((err) => {
reply.boom(500, err);
});

Resources