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
Related
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);
})
I want to enforce password complexity by using the joi-password-complexity package when users register.
https://github.com/kamronbatman/joi-password-complexity
I tried but I got the following error:
(node:14872) UnhandledPromiseRejectionWarning: AssertionError
[ERR_ASSERTION]: Invalid schema content:
(password.$_root.alternatives)
This is the code I'm using:
const mongoose = require("mongoose");
const Joi = require("joi");
const passwordComplexity = require("joi-password-complexity");
const complexityOptions = {
min: 5,
max: 250,
lowerCase: 1,
upperCase: 1,
numeric: 1,
symbol: 1,
requirementCount: 2,
};
const userSchema = new mongoose.Schema({
name: {
type: String,
minlenght: 1,
maxlength: 55,
required: true
},
email: {
type: String,
minlength: 5,
maxlength: 255,
unique: true,
required: true
},
password: {
type: String,
minlength: 5,
maxlength: 1024,
required: true
}
})
const User = mongoose.model("User", userSchema);
function validateUser(user) {
const schema = {
name: Joi.string().min(1).max(55).required(),
email: Joi.string().min(5).max(255).required().email(),
password: passwordComplexity(complexityOptions) // This is not working
}
return Joi.validate(user, schema);
}
exports.User = User;
exports.validate = validateUser;
I also tried to follow this example: https://forum.codewithmosh.com/d/215-joi-password-complexity-problem but it seems outdated since the "new" keyword will throw another error (not a constructor).
Any help is appreciated!
Couldn't reproduce your exact error, but I had the thing working this way:
#hapi/joi: ^17.1.0 (latest at the time of the writing, also works with 16.1.8)
joi-password-complexity: ^4.0.0 (latest as well)
Code:
function validateUser(user) {
// no change here
const schema = Joi.object({
name: Joi.string().min(1).max(55).required(),
email: Joi.string().min(5).max(255).required().email(),
password: passwordComplexity(complexityOptions)
});
// note that we call schema.validate instead of Joi.validate
// (which doesn't seem to exist anymore)
return schema.validate(user);
}
Here is how i solved the issue:
if You are using joi#14.3.1 or older then install joi-password-complexity#2.0.1 then try this code:
User.js model
const mongoose = require("mongoose");
const Joi = require("joi");
const PasswordComplexity = require("joi-password-complexity");
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
email: { type: String, required: true, unique: true },
password: { type: String, required: true }
});
const User = mongoose.model("User", userSchema);
function validateUser(user) {
const schema = {
name: Joi.string()
.min(3)
.max(50)
.required(),
email: Joi.string()
.email()
.max(255)
.required(),
password: new PasswordComplexity({
min: 8,
max: 25,
lowerCase: 1,
upperCase: 1,
numeric: 1,
symbol: 1,
requirementCount: 4
});
};
return Joi.validate(user, schema);
}
module.exports.validate = validateUser;
module.exports.User = User;
This will validate password complexity but for making password REQUIRED you have to validate it in your route...
Users.js route
const _ = require("lodash");
const express = require("express");
const { User, validate } = require("../models/user");
const router = express.Router();
//POST
router.post("/", async (req, res) => {
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
//
if (!req.body.password) return res.status(400).send("Password is required..");
let user = await User.findOne({ email: req.body.email });
if (user) return res.status(400).send("User already registered..");
user = new User(_.pick(req.body, ["name", "email", "password"]));
await user.save();
res.send(_.pick(user, ["_id", "name", "email"]));
});
module.exports = router;
I had to add .default to import the function that returns the Joi object. Using Joi 17.3.0 and joi-password-complexity 5.0.1, this is what worked for me:
const passwordComplexity = require('joi-password-complexity').default;
const schema = Joi.object({
email: Joi.string().min(5).max(255).required().email(),
password: passwordComplexity().required(),
});
Since the passwordComplexity() returns a Joi object, you can write required in a fluent way. Thus, you don't have to write extra validation in the router.
function validateUser(user) {
// no change here
const schema = Joi.object({
name: Joi.string().min(1).max(55).required(),
email: Joi.string().min(5).max(255).required().email(),
password: passwordComplexity(complexityOptions).required()
});
// note that we call schema.validate instead of Joi.validate
// (which doesn't seem to exist anymore)
return schema.validate(user);
}
Versions used of Joi and JPC:
├── ...
├── joi#17.2.1
├── joi-password-complexity#4.2.1
The validation function must be updated to fit with the new updated version of JOI. joi.validate() is no longer supported in Joi v16+
const Joi = require("joi");
const passwordComplexity = require("joi-password-complexity");
function validateUser(user) {
const schema = Joi.object({
name: Joi.string().min(5).max(50).required(),
email: Joi.string().min(5).max(255).required().email(),
password: passwordComplexity(complexityOptions),
});
return schema.validate(user); // NOT >> Joi.validate(user, schema); !!!!!
}
and the complexityOptions can be something like:
const complexityOptions = {
min: 5,
max: 1024,
lowerCase: 1,
upperCase: 1,
numeric: 1,
symbol: 1,
requirementCount: 4,
};
Another way is Regex
const joi = require("joi");
const strongPasswordRegex = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!#$%^&*-]).{8,}$/;
const stringPassswordError = new Error("Password must be strong. At least one upper case alphabet. At least one lower case alphabet. At least one digit. At least one special character. Minimum eight in length")
const schema = joi.object().keys({
username: joi.string().required().min(4).max(15),
password: joi.string().regex(strongPasswordRegex).error(stringPassswordError).required()
});
const notValid = schema.validate({ username: "MHamzaRajput", password: "Admin#admin123" }).error;
if (notValid) {
console.log(notValid.message);
} else {
console.log("payload validated successfully");
}
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()
I'm trying to implement CRUD operations using MEAN stack. I'm facing a problem on getting user by Id. It's showing the status true but it returns an empty document.
This is my model:
const userSchema = new mongoose.Schema({
fullName: {
type: String,
required: 'Full name can\'t be empty '
},
userName: {
type: String,
required: 'user name can\'t be empty ',
unique: true
},
email: {
type: String,
required: 'email can\'t be empty ',
unique: true
});
mongoose.model('User', userSchema);
in my controller:
const mongoose = require('mongoose');
const passport = require('passport');
var ObjectId = require('mongoose').Types.ObjectId;
const User = mongoose.model('User');
module.exports.getuser = (req, res, next) => {
if(!ObjectId.isValid(req.params.id))
return res.status(400).send(`No record with given id : ${req.params.id}`);
User.findById(req.params.id, (err, user) => {
if(!err){ res.status(200).json({status: true, user}); }
else{ console.log('Error in retriving User :' + JSON.stringify(err, undefined, 2)); }
});
}
This is the route:
router.get('/:id', jwtHelper.verifyJwtToken, ctrlUser.getuser);
while checking in the postman I'm getting status: true but it returns a blank document.
I'm not getting what's going on anyone please help.
Thanks in advance!!
There could be several reasons why you're not able to find and return a user. I'd go through this checklist to see what might be occurring:
When you define your schema the required field takes a boolean or a function, not a string. To be safe it would make sense to change your strings to true in order to make sure all new db records contain these fields. (https://mongoosejs.com/docs/schematypes.html#schematype-options)
When you import the model in your controller there is no need to call mongoose.model again; this step is performed in your model file. Make sure you're exporting the mongoose.model('User', userSchema) object in the model file/module and then do a normal const User = require(<pathToModelFile>); in the controller module.
If this still doesn't work...
You'll want to make sure your record is in fact saved in your db. Run a mongo shell in terminal by running $ mongo and use commands found here to use your db and search the User collection: https://docs.mongodb.com/manual/reference/mongo-shell/
This is how I would normally code my model and controllers (with routes):
Model file - Note you do need to require Mongoose
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
fullName: {
type: String,
required: true
},
userName: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
unique: true
});
module.exports = mongoose.model('User', userSchema);
Controller/Router -
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const passport = require('passport');
const User = require('User');
router.get('/:id', jwtHelper.verifyJwtToken, async (req, res) => {
try {
const user = await User.findById(req.params.id);
res.status(200).json({status: true, user});
} catch (e) {
res.status(400).json({err: e});
}
});
module.exports = router;
I am using mongoose v5.2.17.
I was wondering is it possible to have multiple models map to the 1 schema.
For example - I have the following model
const mongoose = require('mongoose');
const validator = require('validator');
const jwt = require('jsonwebtoken');
const _ = require('lodash');
const bcrypt = require('bcryptjs');
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true,
trim: true,
minlength: 1,
unique: true,
validate: {
validator: validator.isEmail,
message: '{VALUE} is not a valid email',
},
},
password: {
type: String,
required: true,
minlength: 6,
},
isTrialUser: {
type: Boolean,
default: true,
},
isAdminUser: {
type: Boolean,
default: false,
}
});
UserSchema.methods.toJSON = function () {
const user = this;
const userObject = user.toObject();
return _.pick(userObject, ['_id', 'email', 'isTrialUser']);
};
UserSchema.pre('save', function (next) {
const user = this;
if (user.isModified('password')) {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (hashErr, hash) => {
user.password = hash;
next();
});
});
} else {
next();
}
});
const User = mongoose.model('User', UserSchema);
module.exports = { User, UserSchema };
Is it possible for me to create another AdminModel where admin specific methods can live?
I also want to return all data from the toJSON method from the AdminModel.
Please let me know if this is possible or if there is a better way to perform such a task
Thanks
Damien
If I am understanding you correctly you want to inherit the UserModel in an AdminModel and decorate that one with extra methods etc. For that you can use util.inherits (or the so called Mongoose discriminators) like so:
function BaseSchema() {
Schema.apply(this, arguments);
this.add({
name: String,
createdAt: Date
});
}
util.inherits(BaseSchema, Schema);
var UserSchema = new BaseSchema();
var AdminSchema = new BaseSchema({ department: String });
You can read more about it in Mongoose docs.
There is also a good article on the mongoose discriminators here