MongooseJS object undefined inside callback function - javascript

I'm trying to write an endpoint for an API that will return all orders for a given user. My issue is that when I try to query the database using mongoose's findById function, the 'user' object is undefined in the callback function and I can't query the orders subdoc. To add to the confusion, I can get it to work if I don't use a callback function, but then I don't have proper error handling.
var mongoose = require('mongoose');
var router = express.Router();
var order_model = require('../models/order');
var user_model = require('../models/user');
router.get('/:userid/order/', function (req, res) {
// This works???
var u = user_model.findById(req.params.userid);
res.json(u.orders);
});
The following code throws the error "TypeError: Cannot read property 'orders' of undefined".
var mongoose = require('mongoose');
var router = express.Router();
var order_model = require('../models/order');
var user_model = require('../models/user');
router.get('/:userid/order/', function (req, res) {
// This throws an error.
user_model.findById(req.params.userid).then(function (err, user) {
if (err) {
res.send(err);
}
res.json(user.orders);
});
});
user.js
var mongoose = require('mongoose');
var ordersSchema = require('./order').schema;
var userSchema = new mongoose.Schema({
name: String,
email: String,
showroom: String,
orders: [ordersSchema]
});
module.exports = mongoose.model('User', userSchema);
order.js
var mongoose = require('mongoose');
var lineItemsSchema = require('./lineitem').schema;
var ordersSchema = new mongoose.Schema({
trackingNumber: Number,
lineItems: [lineItemsSchema]
});
module.exports = mongoose.model('Order', ordersSchema);
Any help / explanation of this behavior would be appreciated. Thanks!

The first parameter of the then callback is user, not err.
Either use a traditional callback:
user_model.findById(req.params.userid, function (err, user) {
if (err) {
res.send(err);
return; // Need to return here to not continue with non-error case
}
res.json(user.orders);
});
Or chain a call to catch on the promise to separately handle errors:
user_model.findById(req.params.userid).then(function (user) {
res.json(user.orders);
}).catch(function(err) {
res.send(err);
});

I usually query like this, it work perfect :
user_model.find(_id : req.params.userid)
.exec((err, user) => {
if(err){
//handle error
}
return res.status(200).json(user.orders);
})
});

Related

TypeError: Cannot read properties of undefined (reading '_id')

I'm working on a personal project and i really need some help
I'm having this error and i don't understand why :(
Here is my code :
//authRoutes.js
const { Router } = require('express');
const authController = require('../controllers/authController');
const { requireAuth } = require('../middleware/authMiddleware');
var Post = require('../models/post')
const router = Router();
router.use(function(req,res, next){
res.locals.user = req.user;
next();
});
router.get('/signup', authController.signup_get);
router.post('/signup', authController.signup_post);
router.get('/login', authController.login_get);
router.post('/login', authController.login_post);
router.get('/logout', authController.logout_get);
router.get("/home", function (req, res) {
res.render("home");
});
router.get("/about", function (req, res) {
res.render("about");
});
router.get("/", requireAuth, function(req,res){
Post.find({userID:req.user._id}).exec(function(err, posts){
if(err){
console.log(err);
}
res.render("posts",{posts:posts})
})
})
router.get("/add", requireAuth, function(req,res){
res.render("addpost")
})
Everything was working fine until I tried to add a new post to the database
This is the part of the code that's causing the error :
router.post("/add",requireAuth, function(req,res){
var newPost = new Post({
title:req.body.title,
content:req.body.content,
userID:req.user._id
})
newPost.save(function(err,post){
if(err){
console.log(err)
res.redirect("/posts")
}
})
})
module.exports = router;
can someone help me?
The error is because in here:
var newPost = new Post({
title:req.body.title,
content:req.body.content,
userID:req.user._id
})
you're trying to access "user._id", but there is not "_id" inside user, so check what is inside user.
Quite literally, it is what it say it is
Cannot read properties of undefined (reading '_id')
This means that there's no _id property inside req.user (the object user inside the req object).
It seems you're not sending _id (maybe your payload is using id instead of _id? Could you share your payload with us?
it seems like req.user is undefined and that is the reason of why it gives you that error. Try to find out where you get your id from! :)
Here is user.js
const mongoose = require('mongoose');
const { isEmail } = require('validator');
const bcrypt = require('bcrypt');
const userSchema = new mongoose.Schema({
email: {
type: String,
required: [true, 'Please enter an email'],
unique: true,
lowercase: true,
validate: [isEmail, 'Please enter a valid email']
},
password: {
type: String,
required: [true, 'Please enter a password'],
minlength: [6, 'Minimum password length is 6 characters'],
}
});
// fire a function before doc saved to db
userSchema.pre('save', async function(next) {
const salt = await bcrypt.genSalt();
this.password = await bcrypt.hash(this.password, salt);
next();
});
// static method to login user
userSchema.statics.login = async function(email, password) {
const user = await this.findOne({ email });
if (user) {
const auth = await bcrypt.compare(password, user.password);
if (auth) {
return user;
}
throw Error('incorrect password');
}
throw Error('incorrect email');
};
const User = mongoose.model('user', userSchema);
module.exports = User;

how doe export work in javaScript wold. hash undefined bcryptjs

Let's say we have two file, user.js users.js in user.js we have. Why can we do module.exports.. we can use in it diff .js file? what does "#returns Promise If callback has been omitted" means it is from the bcrypt.genSalt function?
I also have a github repo, so please take a look if you have a bit of time. after cloning it
stuck in terminal
result { error: null,
value:
{ email: 'max#mail.com',
username: 'max',
password: '1234',
confirmationPassword: '1234' },
then: [Function: then],
catch: [Function: catch] }
hash undefined
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const bcrypt = require('bcryptjs');
const userSchema = new Schema({
email: String,
username: String,
password: String
});
const User = mongoose.model('user', userSchema);
module.exports = User;
module.exports.hashPassword = (password) => {
return hash = bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(password, salt, function(err, hash) {
});
});
};
in users.js we have have
const express = require('express');
const router = express.Router();
const Joi = require('joi');
const User = require('../models/user');
const userSchema = Joi.object().keys({
email:Joi.string().email().required(),
username:Joi.string().required(),
password:Joi.string().regex(/^[a-zA-Z0-9]{3,15}$/).required(),
confirmationPassword:Joi.any().valid(Joi.ref('password')).required()
});
router.route('/register')
.get((req, res) => {
res.render('register');
})
.post(async (req, res, next) => {
try{
const result = Joi.validate(req.body,userSchema);
console.log('result',result);
if(result.error) {
req.flash('error', 'Data is not valid, please try again');
res.redirect('/users/register');
return;
//console.log('result',result);
}
// checking if email is already taken
const user = await User.findOne({'email':result.value.email });
if (user){
req.flash('error','Email is already in use');
res.redirect('/users/register');
return;
}
// console.log('hash',hash);
// Hash the password
const hash = await User.hashPassword(result.value.password);
console.log('hash',hash);
} catch(error) {
next(error);
}
});
module.exports = router;
based the example given by bcrypt
var bcrypt = require('bcryptjs');
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash("B4c0/\/", salt, function(err, hash) {
// Store hash in your password DB.
});
});
adding pic for mongo db
I think the problem lies in this line:
const hash = await User.hashPassword(result.value.password);
This implies that User.hashPassword(result.value.password) should be returning a promise (but it returns a reference to the wrong promise).
module.exports.hashPassword = (password) => {
return hash = bcrypt.genSalt(10, function (err, salt) {
bcrypt.hash(password, salt, function (err, hash) {});
});
};
Perhaps modifying the above to return a promise may help.. Like so:
module.exports.hashPassword = (password) => {
var salt = await bcrypt.genSalt(10);
return bcrypt.hash(password, salt);
};
To answer your question about #returns Promise If callback has been omitted:
Bcrypt methods are asynchronous. Which means they return immediately and process in the background. When the result is available, the function makes this available to the calling code either via a callback function or a promise.
Consider the following API for genSalt from the docs:
genSalt(rounds, minor, cb)
rounds - [OPTIONAL] - the cost of processing the data. (default - 10)
minor - [OPTIONAL] - minor version of bcrypt to use. (default - b)
cb - [OPTIONAL] - a callback to be fired once the salt has been generated. uses eio making it asynchronous. If cb is not specified, a Promise is returned if Promise support is available.
err - First parameter to the callback detailing any errors.
salt - Second parameter to the callback providing the generated salt.
What that says is genSalt can take three arguments: genSalt(rounds, minor, cb)
Sample using callbacks
If the calling code wants the result via a callback, it can pass a function which looks like function(err, salt){} as the cb parameter.
bcrypt.genSalt(rounds, minor, function(err, salt){
if(err){
//Handle error
return;
}
// Salt is available here
console.log(salt);
});
Sample using promises
If the cb parameter is not passed (null or undefined) the function returns a Promise instead.
var promise = bcrypt.genSalt(rounds, minor);
promise
.then(function(salt){
// Salt is available here
console.log(salt);
})
.catch(function(err){
// Handle error
});

bcrypt next() is not defined

var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username:{type: String,lowercase: true, required: true,unique:true},
password:{type:String, required:true},
email:{type:String,required:true,lowercase:true,unique:true},
});
// mongoose middleware
UserSchema.pre('save',(req,res,next)=>{
var user = this;
bcrypt.hash(user.password,null,null,(err,hash)=>{
if(err) return next(err);
user.password = hash;
next();
});
});
module.exports = mongoose.model('User',UserSchema);
below the error i can't find out the error
POST /users 200 58.468 ms - 14
/var/www/html/meanstacktutorial/app/models/user.js:17
next();
^
ReferenceError: next is not defined
at bcrypt.hash (/var/www/html/meanstacktutorial/app/models/user.js:17:9)
at /var/www/html/meanstacktutorial/node_modules/bcrypt-nodejs/bCrypt.js:631:3
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
[nodemon] app crashed - waiting for file changes before starting...
when i make password to encrypt then it gets some error like "next() is not defined " why i don't know exactly ..i have been trying to slove the problem but i couldn't please help me out thank you
The function passed to your pre-save hook should only take next as an argument.
You have also passed in req and res.
Try this instead:
UserSchema.pre('save', (next) => {
var user = this;
bcrypt.hash(user.password, null, null, (err, hash) => {
if(err) return next(err);
user.password = hash;
next();
});
});
I hope this helps.

mongoose: TypeError: [function name] is not a function. when trying to create mongoose instanse

I'm writing a web application with MEAN stack, and I'm getting a headache with mongoose instance.
Here are (piece of) my codes:
my route
var express = require('express');
var router = express.Router();
var accDocService = require('../services/accdoc-services');
router.post('/dailybook', function(req, res) {
accDocService.addAccDoc(req.body, function(error) {
if (error) throw error;
});
});
accdoc-service.js
var accDoc = require('../models/accdoc').accDoc;
console.log(typeof accDoc);
exports.addAccDoc = function(accDoc, next) {
var newAccDoc = new accDoc({
number: '45645'
});
newAccDoc.save(function(error) {
if (error) throw error;
console.log("doc created");
});
};
accdoc.js (the model file)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var accDocSchema = new Schema({
number: String
});
var accDoc = mongoose.model('accDoc', accDocSchema);
module.exports = {
accDoc: accDoc
};
After sending the post request, I'm getting TypeError: accDoc is not a function
Also, console.log(typeof accDoc); in second file, returns function.
EDIT 1
In accdoc-services, if I move var AccDoc = require('../models/accdoc'); to the addAccDoc function, everything works fine.
Am I missing some node.js stuff here? I'm watching a tutorial video from Lynda that there is not some scope problem like this.
here is an image from Lynda tutorial
You are missing the new keyword for creating a model instance of accDoc
var accDoc = require('../models/accdoc').accDoc;
console.log(typeof accDoc);
exports.addAccDoc = function(accDoc, next) {
var newAccDoc = new accDoc({ // HERE new was missing!
number: '45645'
});
newAccDoc.save(function(error) {
if (error) throw error;
console.log("doc created");
});
};

MongoDB - Getting error while connect with local data base

I am trying to create a User list when user submit their details. In app.js I have the function for that.
like this:
app.post('/addList', userList.submit);
I am calling my function which is nested in userList.submit:
var sendList = require('../model/model');
exports.list = function(req, res){
res.send("respond with a resource this is from list file");
};
exports.addList = function(req, res, next){
res.render('index', {title:'title from list.js'});
};
exports.submit = function(req,res,next){
var name = req.body.name,
dept = req.body.dept;
sendList.create({
name:name,
dept:dept
}, function(error){
console.log('Erros is ', error);
if (error) return next(error);
res.redirect('/');
});
};
In the model folder, model.js has the function as follows:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/user_list');
var schema = new Schema({
name:String,
dept:String
});
module.exports = mongoose.model('User', schema);
But I am getting error saying:
var schema = new Schema({
^
ReferenceError: Schema is not defined
What is this mean? where I made the mistake? any one figure out and help me to solve this?
Schema is defined as a property of mongoose. It's not there in the global scope of nodejs.
var schema = new mongoose.Schema({
name:String,
dept:String
});
Schema is part of an application or is a property of mongoose. It has nothing to do with db, it's only mapping db into js objects.
you have to change the code : = new mogoose.schema ({ what ever you want ..

Categories

Resources