Cannot read property 'users' of undefined - javascript

I'm new to MongoDB and have a database of users. I'm trying it such that a user can click on a button of their favorite shoes and it updates the database. My schema is as follows:
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
// define the schema for our user model
var userSchema = mongoose.Schema({
local : {
email : String,
password : String,
},
});
// methods ======================
// generating a hash
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// checking if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
// create the model for users and expose it to our app
module.exports = mongoose.model('User', userSchema);
Posting DB function:
exports.addToFavs = function(req, res) {
var size_result = req.query.size;
var brandToFind = req.query.brandToFind;
req.db.users.update({email: req.user.email}, {$set: favoriteShoes[{name: brandToFind, size: size_result}]}); /*, function(error, favoriteShoes) {
if (error) return next(error);
if (!favoriteShoe) return next(new Error('Failed to save')); */
console.info('Added %s with id=%s', brandToFind, size_result);
res.redirect('/favorites');
//})
};
HTML Button:
<form action="/result" method="post">
<center><button>Save to Favorites</button></center>
</form>
Appropriate Routes:
app.post('/result', searchResults.addToFavs);
I'm really confused about how to get this to work... somehow it can't read by db table "users" (validated through the console that this is what the table is called) so trying to get it to work but it's not working...

Related

MongooseJS object undefined inside callback function

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

400 Bad Request when i register a new user in NodeJS via Mongoose using PassportJS

Am creating a registration form where user needs to enter details of his emailid(username),password,DOB,Address,phoneno. All fields are mandatory here emailid acts as an username. I have designed my Mongoose Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var User = new Schema({
username: String,
password: String,
phoneno: {
type: Number,
unique: true,
required: true
},
Address : {
type: String,
required: true
},
Dob: {
type: String,
required: true
}
},{
timestamps: true
});
User.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', User);
My user router is given below
var express = require('express');
var UserDetails = express.Router();
var userSchema=require('../models/user');
var passport = require('passport');
const mongoose = require('mongoose');
var Verify = require('./verify');
UserDetails.post('/register', function(req, res, next) {
var newUser = new userSchema({
username : req.body.email,
Dob : req.body.dob,
Address : req.body.address,
phoneno : req.body.phoneno
});
userSchema.register(newUser,req.body.password, function(err, user) {
if (err) {
console.log(err);
return res.status(500).json({err: err});
}
passport.authenticate('local')(req, res, function () {
console.log(req);
console.log(res);
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
This is the json object am sending via PostMan
{"email":"kannaa.in","password": "abcdef","phoneno":96930,"address":"396 SM Road","dob":"14-05-1992"}
But in the console and postman it says bad request if i try to perform the operation.However it stores the value in DB. I couldn't find out the error.
So after no one answered i found out myself what is the error about PassportJS expects the request to contain req.body.username it doesn't matter how many other datas you send it needs req.body.username from the request side. So all i had to change was rather than email i set it as username in postman and it worked like charm.
My postman Data
{"username":"kannaa.in","password": "abcdef","phoneno":96930,"address":"396 SM Road","dob":"14-05-1992"}

invalidate a validation from a nested schema virtual mongoose

I have my parent schema defined like this:
User.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var PasswordSchema = require('./Password');
var UserSchema = new Schema({
name: { type: String, required: true },
password: PasswordSchema
});
mongoose.model('User', UserSchema);
My children schema defined like this:
Password.js:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var crypto = require('crypto');
var PasswordSchema = new Schema ({
_id: false,
hashedPassword: { type: String, required: true },
salt: { type: String, default: '' }
});
var passwordRegex = /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,24}$/;
PasswordSchema.virtual('password')
.set(function (password) {
if (passwordRegex.test(password))
{
this.invalidate('password', 'Invalid password format');
}
});
mongoose.model('Password', PasswordSchema);
module.exports = PasswordSchema;
Now I used these Models schema in my controller like this:
user.js:
require('../models/User');
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var User = mongoose.model('User');
var Password = mongoose.model('Password');
router.post('/register', function (req, res, next) {
var user = new User(req.body);
var password = new Password({ password: 'abcd1234' });
console.log(password.$__.validationError.errors['hashedPassword']); // Here it works I got the validation error
user.password = password;
user.password.$__.validationError = password.$__.validationError; // WORKAROUND
console.log(user.password.$__.validationError.errors['hashedPassword']); // Here it doesn't work no validation error anymore ...
user.save(function (err) {
if (err)
console.log(":(");
else
console.log(":)");
});
});
module.exports = router;
Question:
So my problem now is that no matter what password I send to my children virtual it doesn't invalidate the process. How could I invalidate the mongoose save action from a children virtual ? Is there an other better option ?
Question Updated:
In user.js why the variable password has the validation error and when I assign it to user.password I don't have the validation error anymore ? How can I correct it ?
** Update 2:**
I have found a workaround see user.js: I just assign the required property to generate validation error. But it looks really not clean is there another way?
Here is one good example https://gist.github.com/swaj/1350041, refactor it as below
PasswordSchema.virtual('password')
.get(function(){
return this._password;
})
.set(function (password) {
this._password = password;
// invoke crypto to hash and encrypt password, then assign it to hashedPassword
this.hashedPassword = password; // this is just for test
});
PasswordSchema.path('hashedPassword').validate(function(v) {
if (v) {
if (passwordRegex.test(v)) {
this.invalidate('password', 'Invalid password format');
}
}
if (!v) {
this.validate('password', 'password required');
}
}, null);
Test codes
var user = new User({name: 'dd'});
user.password = new Password({password: 'asdfASF123444'});
user.save(function (err) {
if (err)
console.log(err);
else
console.log("save user successfully");
});
Validation error is
{ [ValidationError: User validation failed]
message: 'User validation failed',
name: 'ValidationError',
errors:
{ password:
{ [ValidatorError: Invalid password format]
properties: [Object],
message: 'Invalid password format',
name: 'ValidatorError',
kind: 'user defined',
path: 'password',
value: undefined } } }
Per invalidate source code
Document.prototype.invalidate = function (path, err, val) {
if (!this.$__.validationError) {
this.$__.validationError = new ValidationError(this);
}
// ...
We know invalidate function belong to Document.
password.$__.validationError.errors['hashedPassword']
You define the validation for PasswordSchema, not in UserSchema. so user.password.$__.validationError.errors['hashedPassword'] is not valid.
Test your code with
var user = new User({name: 'dd'});
user.password = new Password({password: 'asdfwe32113'});
user.save(function (err) {
if (err)
console.log(err);
else
console.log("save user successfully");
});
Validation will be triggered, however, with this code
`user.password = new Password({hashedPassword: 'asdfwe32113'});`
This validation is NOT triggered.
Because for virtual field, only the correct virtual name field is updated then the .set function could be called.
Also please add those codes to virtual('password'), to make sure the hashedPassword could be set correctly.
if (passwordRegex.test(password)) {
this.invalidate('password', 'Invalid password format');
}else {
this.hashedPassword = password;
}
For the second question, require('../models/User'); must be invoked before mongoose.model() to make sure the User.js is parsed firstly, and the User could be added into mongoose.model in User.js. So in user.js could find this User model from mongoose. JavaScript is an interpreted programming language, so we should tell the JS engine the file parsed order in this way.

How to inserting a document with field referencing document in another collection

I am currently attempting to create a .post function for a schema with document reference. However, I am not sure how I can retrieve the ObjectID of the document reference from another collection.
Board.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var BoardSchema = new Schema({
boardname: String,
userid: {type: Schema.ObjectId, ref: 'UserSchema'}
});
module.exports = mongoose.model('Board', BoardSchema);
User.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: String
});
module.exports = mongoose.model('User', UserSchema);
routes.js
router.route('/boards')
.get(function(req, res) {
Board.find(function(err, boards) {
if(err)
res.send(err);
res.json(boards);
});
})
.post(function(req, res) {
var board = new Board();
board.boardname = req.body.boardname;
User.find({username: req.body.username}, function(err, user) {
if(err)
res.send(err);
board.userid = user._id;
});
board.save(function(err) {
if(err)
res.send(err);
res.json({message: 'New Board created'});
});
});
To create the board, I include a boardname and a username in my request. Using the username, I do a User.find to find the specific user and assign it to board.userid. However, this does not seem to be working as board.userid does not appear.
Any help would be greatly appreciated!
Thank you!
EDIT
A better explanation of what is required is that I have an existing User collection. When I want to add a new document to Board, I would provide a username, from which I would search the User collection, obtain the ObjectId of the specific user and add it as userid to the Board document.
I believe you are looking for population
There are no joins in MongoDB but sometimes we still want references
to documents in other collections. This is where population comes in.
Try something like this:
//small change to Board Schema
var BoardSchema = new Schema({
boardname: String,
user: {type: Schema.ObjectId, ref: 'User'}
});
//using populate
Board.findOne({ boardName: "someBoardName" })
.populate('user') // <--
.exec(function (err, board) {
if (err) ..
console.log('The user is %s', board.user._id);
// prints "The user id is <some id>"
})
Sorry, I solved a different problem previously. You'll probably want to use the prevoius solution I provided at some point, so I'm leaving it.
Callbacks
The reason the userid is not on the board document is because User.find is asynchronous and is not assigned at the moment board.save(...) is called.
This should do the trick:
(Also, I added a couple of returns to prevent execution after res.send(...))
.post(function(req, res) {
var board = new Board();
board.boardname = req.body.boardname;
User.find({username: req.body.username}, function(err, user) {
if(err)
return res.send(err); //<-- note the return here!
board.userid = user._id;
board.save(function(err) {
if(err)
return res.send(err); //<-- note the return here!
res.json({message: 'New Board 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