I'm trying to use joi module on mongoose schema but it doesn't work
everything works except joi validation
the module was installed and required.
schema:
const mongoose = require("mongoose");
const joi = require("joi");
const userSchima = new mongoose.Schema({
name: {
type: String,
required: [true, "use must have a name"],
unique: true,
trim: true,
},
email: {
type: String,
required: [true, "use must have an email"],
unique: true,
trim: true,
},
password: {
type: String,
required: [true, "use must have an password"],
},
});
const User = mongoose.model("User", userSchima);
// const validateUser = (User) => {
// const schema = {
// name: joi.string().min(2).max(15),
// email: joi.types.String().email().required(),
// password: joi.minOfUppercase(1).minOfNumeric(2).noWhiteSpaces().required(),
// };
// return joi.validate(User, schema);
// };
// module.exports = validateUser;
module.exports = User;
create async fun from the controller:
i didn't add the catch method because of to much code here
exports.creatUser = async (req, res) => {
try {
const newUser = await User.create(req.body);
res.status(200).json({
status: "success",
data: {
user: newUser,
},
});
}
thanks from help
Related
I am trying to save password in MongoDB but have error:
Error: User validation failed: password: Path `password` is required.
Model:
const {Schema, model} = require('mongoose');
const UserSchema = new Schema({
email: {type: String, unique: true, required: true},
password: {type: String, required: true},
isActivated: {type: Boolean, default: false},
activationLink: {type: String},
})
module.exports = model('User', UserSchema)
create user:
const bcrypt = require('bcryptjs');
const UserModel = require('../models/user-model');
...
const hashPassword = await bcrypt.hash(password, 10);
console.log(`email => ${email} pass => ${hashPassword}`);
const user = await UserModel.create({email, hashPassword});
Log shows that password hash created:
email => lll#google.com pass => $2a$10$4IV2Q0ZncWHInfT89Fwl.eCxCgvykvY.uqlvq0GNSeDJ/6Q83T7nK
const user = await UserModel.create({email, hashPassword});
If you pass hashPassword variable, it will take as hashPassword field.
Change your code like this:
const hashPassword = await bcrypt.hash(password, 10);
const user = await UserModel.create({email, password: hashPassword});
Re-create your model using these lines of code
const mongoose = require('mongoose')
const bcrypt = require('bcryptjs')
const userSchema = mongoose.Schema(
{
email: {
type: String,
required: true,
lowercase: true,
trim: true
},
password: {
type: String,
required: false,
minlength: 8
},
activationLink: {
type: String,
trim: false
},
isActivated: {
type: Boolean,
default: false
}
},{
timestamps: true
}
)
userSchema.methods.isPasswordMatch = async function (password) {
const user = this
return bcrypt.compare(password, user.password)
}
userSchema.pre('save', async function (next) {
const user = this
if (user.isModified('password')) {
user.password = await bcrypt.hash(user.password, 8)
}
next()
})
const User = mongoose.model('user', userSchema)
module.exports = User
I created a Blog and for its slug, I install slugify and require it.
I'm trying to save a new blog post in MongoDB with mongoose, but I am getting this error: slug: ValidatorError: Path slug is required.
I validate slugify from the tutorial from Web Dev Simplified Youtube Channel but it is not working.
Here is the code :
// getting-started.js
const mongoose = require("mongoose");
const slugify = require("slugify");
main().catch((err) => console.log(err));
async function main() {
await mongoose.connect(process.env.ATLAS);
}
// Schema
const blogSchema = new mongoose.Schema({
title: {
type: String,
required: true,
unique: true,
},
description: {
type: String,
required: true,
},
slug: {
type: String,
required: true,
unique: true,
},
});
blogSchema.pre("validate", (next) => {
if (this.title) {
this.slug = slugify(this.title, { lower: true, strict: true });
}
next();
});
// Model
const Blog = mongoose.model("Blog", blogSchema);
Your code is correct, replace the arrow function with the regular function because "this" doesn't work with arrow functions and remove required: true from slug field.
blogSchema.pre("validate", function (next) {
if (this.title) {
this.slug = slugify(this.title, { lower: true, strict: true });
}
next();
});
I want to implement text search on my app, and find documents where the field login matches the searched term,
I did the code below and I have no errors but the result in the route is always an empty array, there must be an error somewhere
Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
created_at: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
display_name: {
type: String,
required: true,
index: true,
},
login: {
type: String,
required: true,
index: true,
},
});
UserSchema.index({ login: "text", display_name: "text" });
User = mongoose.model("users", UserSchema);
User.createIndexes();
module.exports = User;
Route
router.post("/users", async function (req, res) {
const { search } = req.body;
const users = await User.find({ $text: { $search: search } });
res.send(users);
});
I have 2 models in relation a User model and a Task model each user have inside an empty task array and I want a function that get the user by email and push a new task to the users task array I tried a lot but I don't made that function to work so I need some help here is my code.
User model:
const { Schema } = mongoose;
//connecting mongoose to mongoDB
mongoose.connect("mongodb+srv://tudor:tudor#cluster0.gbojb.mongodb.net/<dbname>?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false });
const { Post } = require("./PostModel")
const userSchema = new Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
minlength: [5, 'The password should have more then 5 characters']
},
age: {
type: Number,
required: true,
},
description: {
type: String,
required: true,
maxlength: [300, 'Description should have less then 300 characters']
},
tasks: [{
type: Schema.Types.ObjectId,
ref: "task"
}]
})
const User = mongoose.model('User', userSchema);
exports.User = User
task model
const mongoose = require("mongoose")
const Schema = mongoose.Schema
let TaskSchema = new Schema({
content: String,
owner: {
type: Schema.Types.ObjectId,
ref: "User"
}
})
module.exports = mongoose.model("Task", TaskSchema)
And here I want to make the function :
const createNewTask = async (req, res, next) => {
const userEmail = req.params.id;
}
This is how your function will work:
const createNewTask = async (req, res, next) => {
const userEmail = req.params.id;
// find user first by email
const userData = await User.findOne({email: userEmail});
// add check here if user exist or not (not writing it for now)
// now create task by extract task payload (assuming you have detail in body)
const taskData = await Task.create({
content: req.body.content,
owner: userData._id,
});
// now push task id in user
await User.updateOne({
email: userEmail
}, {
$push: {tasks: taskData._id},
});
}
There can be some errors since didn't tested it but you get the idea how to do it.
The user model
```
const crypto = require('crypto');
const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const UserSchema = new mongoose.Schema(
{
username: {
type: String,
unique: [true, 'Username already taken'],
required: [true, 'Please enter a usernam']
},
dob: String,
email: {
type: String,
required: [true, 'Please provide your email'],
unique: true,
lowercase: true,
validate: [validator.isEmail, 'Please provide with a mail']
},
profile_img: String, //url of the image |||Should think how we have store the image|||
password: {
type: String,
required: [true, 'Please provide with a password'],
minlength: 8,
select: false
},
passwordConfirm: {
type: String,
required: [true, 'Please confirm your password'],
validate: {
validator: function(el) {
return el === this.password;
},
message: "Password don't match"
}
},
passwordChangedAt: Date,
passwordResetToken: String,
passwordResetExpires: Date,
areaOfInterest: [], //array of String
friends: [
{
type: mongoose.Schema.ObjectId,
ref: 'User'
}
],
isBoarded: { type: Boolean, default: false },
createdAt: {
type: Date,
default: Date.now()
}
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true }
}
);
//virtual populate
UserSchema.virtual('posts', {
ref: 'Post',
foreignField: 'userId',
localField: '_id'
});
UserSchema.pre('save', async function(next) {
if (!this.isModified('password')) return next();
this.password = await bcrypt.hash(this.password, 12);
this.passwordConfirm = undefined;
next();
});
UserSchema.pre('save', function(next) {
if (!this.isModified('password') || this.isNew) return next();
this.passwordChangedAt = Date.now() - 1000;
next();
});
UserSchema.methods.correctPassword = async function(passwordToMatch, password) {
return await bcrypt.compare(passwordToMatch, password);
};
UserSchema.methods.changedPasswordAfter = function(JWTTimeStamp) {
if (this.passwordChangedAt) {
const changedTimeStamp = parseInt(
this.passwordChangedAt.getTime() / 1000,
10
);
return JWTTimeStamp < changedTimeStamp;
}
return false;
};
This is where the method is added using the methods property before the exporting the model
UserSchema.methods.createPasswordResetToken = function() {
const resetToken = crypto.randomBytes(32).toString('hex');
this.passwordResetToken = crypto
.createHash('sha256')
.update(resetToken)
.digest('hex');
// console.log({ resetToken }, this.passwordResetToken);
this.passwordResetExpires = Date.now() + 10 * 60 * 1000;
return resetToken;
};
const User = mongoose.model('User', UserSchema);
module.exports = User;
And method is called in this fuction
const { promisify } = require('util');
const crypto = require('crypto');
const jwt = require('jsonwebtoken');
const User = require('../models/userModel');
const catchAsync = require('../utils/catchAsync');
const AppError = require('../utils/appError');
const sendEmail = require('../utils/email');
exports.forgotPassword =async (req, res, next) => {
console.log(User.schema.methods);
const user = await User.findOne({ email: req.body.email });
console.log(user);
if (!user) {
return next(new AppError('No user with that email address', 404));
}
Here is where the error occurs where I have called the method with the error "user.createPassswordResetToken is not a function","stack":"TypeError: user.createPassswordResetToken is not a function\n at controllers/authController.js:117:27\n at processTicksAndRejections (internal/process/task_queues.js:93:5)"
In the above mentioned error this is the line no which it points to
const resetToken = user.createPassswordResetToken();
await user.save({ validateBeforeSave: false });
const resetURL = `${req.protocol}://${req.get(
'host'
)}/api/v1/users/resetPassword/${resetToken}`;
const message = `Forgot your Password? Submit your new password and confirm your password at ${resetURL}.\n If you didn't forgot your password, please ignore this email.`;
The console log of User.schema.methods is
{
correctPassword: [AsyncFunction (anonymous)],
changedPasswordAfter: [Function (anonymous)],
createPasswordResetToken: [Function (anonymous)]
}
the method in user schema is createPasswordResetToken, while in the function you called another non existing function createPassswordResetToken
use createPasswordResetToken rather than createPassswordResetToken