mongoose-unique-validator ReferenceError: User is not defined - node.js

I'm new to Node.js so I can't understand what I need to add, to make the default example from mongoose-unique-validator work. Here it is:
const mongoose = require('mongoose'),
uniqueValidator = require('mongoose-unique-validator'),
userSchema = mongoose.Schema({
username: { type: String, required: true, unique: true },
room: { type: String, required: true },
});
userSchema.plugin(uniqueValidator);
const user = new User({ username: 'JohnSmith', room: 'asd');
user.save(function (err) {
console.log(err);
});
The part with the user is not working, because of ReferenceError: User is not defined.
As far as I understand, the user part is the part that the library user should define, but I don't know what should be in there to make it work.
TL; DR:
I just want to make an example work.
Thanks.
Update:
Ok, so I've added this line of code:
const User = mongoose.model('Model', userSchema);
and it does not trows an error anymore. But it does not notify that username is not unique. It does not work yet. I want to check a valid username for the room. And that's all.

you didn't define your model collection ("USER") try this:
const mongoose = require('mongoose'),
uniqueValidator = require('mongoose-unique-validator'),
userSchema = mongoose.Schema({
username: { type: String, required: true, unique: true },
room: { type: String, required: true },
});
userSchema.plugin(uniqueValidator);
module.exports.User = mongoose.model('User', UserSchema);
then :
const user = new User({ username: 'JohnSmith', room: 'asd');
user.save(function (err) {
console.log(err);
})

Related

how to return the user email

I have created post route to store posts in the database. It's a protected route so user can store post only after entering the login details. When I post in postman, I've seen that the user email is not returned in the object. Even in the mongodb collection, I don't see the email associated with the post. How do I include the email as well with the post object. I don't want the user to enter the email again and again when posting because they have already logged in. So I kinda want to store the email automatically with the post. Hope I make sense. Can someone help me with this?
Right now the object is kinda stored like this in the posts collection in mongodb
_id: ObjectId("5f1a99d3ea3ac2afe5"),
text: "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. ",
user:ObjectId("5f1a99d3eac2c82afe5"),
age:20,
country:"India",
gender:"male",
date:2020-07-24T08:23:35.349+00:00,
__v:0
I want the email too in the above object.
Post model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema ({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
text: {
type: String,
required: true
},
name: {
type: String
},
email: {
type: String
}
,
age: {
type: Number,
required: true
},
gender: {
type: String,
required: true
},
country: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
})
module.exports = Post = mongoose.model('post', PostSchema)
post route
const express = require('express');
const router = express.Router();
const auth = require('../../middleware/auth')
const { check, validationResult} = require('express-validator');
const User = require('../../models/User')
const Post = require('../../models/Post')
router.post('/', [auth, [
check('text', 'Text is required').not().isEmpty()
]], async (req,res)=>{
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({errors: errors.array()})
}
try {
const user = await (await User.findById(req.user.id)).isSelected('-password')
const newPost = new Post({
text: req.body.text,
name: user.name,
user: req.user.id,
age: req.body.age,
country: req.body.country,
gender: req.body.gender,
email: req.user.email // this email is not stored with the post and I want this to be automatically posted in the collection without the user having to type it again to save the post
})
const post = await newPost.save();
res.json(post);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error')
}
})
module.exports = router;
User model
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
})
module.exports = User = mongoose.model('user', UserSchema);
Change isSelected to select
const user = await (await User.findById(req.user.id)).isSelected(password')
What I potentially see the problem here is, once you have grabed the object of user, you're still referring to req.user.email instead of user.email.
If that does not solve your problem, try to console.log the user returned from after User.findById
Update:
You can see here that isSelected returns boolean. So you're essentialy getting true for having password field in user. Also instead of req.user.email use user.email

Validation with MongooseJS causing NodeJS app to crash

I'm trying to find a better way of performing this validation. I have the user schmea setup and I'm trying to get the age validation working properly as to not cause the app to crash. You'll have to forgive me as I'm still relatively new to the language, so I may not be explaining it 100%. However, here is the User schema I created.
const mongoose = require('mongoose')
const validator = require('validator')
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
age: {
type: Number,
default: 0,
validate(value) {
if(value < 13){
throw new Error('You must be over the age of 13 to register for this site!')
}
}
},
email: {
type: String,
unique: true,
required: true,
trim: true,
lowercase: true,
validate(value){
if (!validator.isEmail(value)) {
throw new Error('Email is invalid')
}
}
},
password: {
type: String,
required: true,
trim: true,
minlength: 7,
validate(value){
if (value.toLowerCase().includes('password')) {
throw new Error('Password cannot contain "password"')
}
}
},
tokens: [{
token: {
type: String,
required: true
}
}]
})
userSchema.virtual('tasks', {
ref: 'Task',
localField: '_id',
foreignField: 'owner'
})
userSchema.methods.generateAuthToken = async function () {
const user = this
const token = jwt.sign({ _id: user._id.toString() }, 'thisismynewcourse')
user.tokens = user.tokens.concat({ token })
await user.save()
return token
}
userSchema.statics.findByCredentials = async (email, password) => {
const user = await User.findOne({ email })
if (!user) {
throw new Error('Unable to login')
}
const isMatch = await bcrypt.compare(password, user.password)
if (!isMatch) {
throw new Error('Unable to login')
}
return user
}
//Hash the plain text password before saving
userSchema.pre('save', async function(next) {
const user = this
if (user.isModified('password')) {
user.password = await bcrypt.hash(user.password, 8)
}
next()
})
userSchema.methods.toJSON = function () {
const user = this
const userObject = user.toObject()
delete userObject.password
delete userObject.tokens
return userObject
}
const User = mongoose.model('User', userSchema)
module.exports = User
The exact area that I'm trying to hone in on is in the age section, I'm trying to validate ages 13 or older, and when I run a test user creation through post man it performs the validation correctly, but it stops the application with the following:
UnhandledPromiseRejectionWarning: ValidationError: User validation failed: age: You must be over the age of 13 to register
Is there a way that I can prevent the application from crashing or should I perform the validation else where? Thanks in advance.
Normally the validation is performed in another file. This can be considered to be a service. But it should pass through a controller first if you want to do it properly. Here is an example of a simple blog post schema I made. You can see the function at the bottom runs every time before I send it to the database.
This is how it looks like in my schema file looks like which is located in folder called models.
// Requiring modules
const mongoose = require('mongoose');
// Initializing Schema
var Schema = mongoose.Schema;
// Creating a data model
const schema = new Schema({
shopname : {type: String, required:true},
address : {type: String, required:true},
review : {type: String, required:false},
image : {type: String, required:false},
originalname: {type: String, required:false},
filename: {type: String, required:false},
mimetype: {type: String, required:false},
size : {type: String, required:false},
updatedAt: {type: Date, required:false},
createdAt: {type: Date, required:false}
})
// Settings up the process before the data is sent to mongoDB.
// This process is call everytime 'save' is called.
// it sets the data for createdAt and updatedAt.
schema.pre('save', function(next){
if (!this.createdAt){
this.createdAt = new Date();
}else{
this.updatedAt = new Date();
}
next();
})
// Exports module
module.exports = mongoose.model("Blog", schema);

schema.methods is not a function

I have been trying to create a method on my user schema in mongoose, however it keeps saying method is not a function and I have no idea why. I am fairly new to mongoose and express, and I'm pretty sure I have my files set up currently so I don't know what could be causing this issue. As a last attempt, I tried switching to arrow functions , but that didn't work either.
user routes file
const router = require("express").Router();
let user = require("../models/user_model");
const Joi = require("#hapi/joi");
// GET dreams
// POST dreams
// DELETE dreams
// UPDATE dreams
router.route("/").get((req, res) => {
console.log(user.addType());
res.send("hello this is a users page");
});
user model file
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema(
{
username: {
type: String,
required: true,
unique: true,
trim: true,
min: 3
},
password: {
type: String,
trim: true,
required: true,
min: 6
}
},
{
timestamps: true
}
);
userSchema.methods.addTypes = function() {
console.log("woof");
};
userSchema.methods.joiValidate = data => {
let Joi = require("#hapi/joi");
const schema = {
username: Joi.string()
.min(6)
.required(),
password: Joi.string()
.min(6)
.required()
};
return schema.validate(data);
};
module.exports = mongoose.model("User", userSchema);
UPDATE! Other than having typo on your code, you also need to create an instance of your model ('user'). You cannot just call the function of the model.
let user = new user({ // Create an instance first
username: 'Tester',
password: '12345678'
})
console.log(user.addType())
you declared
addTypes()
Cheers

Error while saving data in MongoDB atlas with mongoose

I'm trying to save data in the MongoDB atlas with node.js and mongoose.
Every time I use MySchema.save(), Data is inserting But I'm also getting the error:
UnhandledPromiseRejectionWarning: MongoWriteConcernError: No write concern mode named 'majority;' found in replica set configuration
Also, there is no duplicate entry, Data is also inserting But I'm also getting the error
let User = require('../models/users.models');
const username = req.body.username;
const newUser = new User({username});
newUser.save()
.then(() => res.json('user added!'))
.catch(err => res.status(400).json('Error: ' + err));
User model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
var userSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
trim: true,
minlength: 3
},
},
{
timestamps: true
});
const User = mongoose.model('User', userSchema);
module.exports = User;
I know it was asked 2 months ago, but for those who will encounter the same issue.
You are mistakenly entering a wrong char at the end of the URI string:
mongodb+srv://${ user }:${ password }#track-mkahl.mongodb.net/test?retryWrites=true&w=majority;
You need to delete the ; after the word majority.
This helped me.
const schema = new Schema({ name: String }, {
writeConcern: {
w: 'majority',
j: true,
wtimeout: 1000
}
});
https://mongoosejs.com/docs/guide.html#writeConcern
"mongoURI" : "mongodb+srv://${ user }:${ password }#cluster0.mde0j.mongodb.net/cluster0?retryWrites=true&w=majority "
I get the same error with this in default.json its simple error just delete the &w=majority part at the end and it will be solved
for me it was also in the URI string like #Yossi Saadi has suggested, it's just that I had majoritys written there instead of majority
I think there's something wrong with this line.
let User = require('../models/users.models');
I have created a solution for you.
/models/user.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
mongoose.connect("mongodb://localhost/stack-overflow", { useNewUrlParser: true })
var userSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
trim: true,
minlength: 3
},
},
{
timestamps: true
});
const User = mongoose.model('User', userSchema);
module.exports = User
/routes/userroute.js
const User = require("../models/user")
// Imagine run() as an asynchronous request handler
async function run() {
try {
const user1 = new User({ username: "lidafafnus" })
user1.save((err,result) => {
console.log(err, result)
})
} catch(error) {
console.log(error)
}
}
run()

How to automatically create a required field in mongoose

I have a mongoose schema that looks like this:
var userSchema = new Schema({
username: {type: String, required: true, index: {unique: true}},
usernameCanonical: {type: String, required: true, index: {unique: true}}
});
userSchema.pre("save", function () {
this.usernameCanonical = this.username.toLowerCase();
return next();
});
I want to be able to create new users by only entering a username, and let usernameCanonical get generated by the model automatically.
var user = new User({
username: "EXAMPLE_USERNAME"
});
user.save()
When I try to do this I get a validation error from mongoose saying that usernameCanonical is required.
Path `usernameCanonical` is required.
The problem seems to be that the pre-save hooks get called after validation. I don't want to have to manually add a canonical username every time I save a new user. I also don't want to remove the required option from the schema.
Is there some way to get a mongoose model to automatically generate a required field? Adding a default value to the usernameCanonical field in the schema seems to prevent the validation error, but it feels like a hack.
As levi mentioned, you should use the validate() hook:
Save/Validate Hooks
Check this working example based on your code:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
username: {type: String, required: true, index: {unique: true}},
usernameCanonical: {type: String, required: true, index: {unique: true}}
});
userSchema.pre('validate', function () {
if ((this.isNew || this.isModified) && this.username) {
this.usernameCanonical = this.username.toLowerCase();
}
});
const User = mongoose.model('user', userSchema);
mongoose.connect('mongodb://localhost:27017/uniqueTest')
.then(() => {
// create two users
const user1 = new User({
username: 'EXAMPLE_USERNAME-1'
});
const user2 = new User({
username: 'EXAMPLE_USERNAME-2'
});
return Promise.all([
user1.save(),
user2.save()
]);
})
.then(() => {
// update username
return User.findOne({ username: 'EXAMPLE_USERNAME-1' })
.then((user) => {
user.username = 'EXAMPLE_USERNAME_UPDATED-1';
return user.save();
});
})
.then(() => mongoose.connection.close())
.then(() => console.log('script finished successfully'))
.catch((err) => {
console.error(err);
mongoose.connection.close()
.then(() => process.exit(1));
});
I hope this helps.

Resources