I'm learning the MERN stack and trying to create an authentication, but now I have a problem, whenever I'm trying to register, I have an error 'TypeError: User.create is not a function'.
I think that I have a problem with user model or export. Please help
INDEX.JS
const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const dotenv = require("dotenv");
const app = express();
const User = require("./models/User");
dotenv.config({ path: "./.env" });
app.use(express.json());
app.use(cors());
mongoose.connect(process.env.MBD_CONNECT, { useNewUrlParser: true }, (err) => {
if (err) return console.error(err);
console.log("Connected to MongoDB");
});
app.post("/api/registr", async (req, res) => {
console.log(req.body);
try {
const user = await User.create({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: req.body.password,
});
res.json({ status: "ok" });
} catch (err) {
console.log(err);
res.json({ status: "error", error: "Duplicate email" });
}
});
app.post("/api/login", async (req, res) => {
const user = await User.findOne({
email: req.body.email,
password: req.body.password,
});
if (user) {
return res.json({ status: "ok", user: true });
} else {
return res.json({ status: "error", user: false });
}
});
app.listen(3001, () => {
console.log("SERVER RUNS PERFECTLY!");
});
USER.JS (MODEL)
const mongoose = require("mongoose");
const User = new mongoose.Schema({
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
const model = mongoose.model("UserData", User);
module.exports = User;
You're exporting the schema, not the model. create is a method of mongoose Model class, see document here.
const model = mongoose.model("UserData", User);
module.exports = User; // <------ problem here
It should be:
const model = mongoose.model("UserData", User);
module.exports = model;
Your model file please update with the following code snip
const mongoose = require("mongoose");
const User = new mongoose.Schema({
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
}, { collection : 'UserData'});
const model = mongoose.model("UserData", User);
module.exports = User;
Related
I'm trying to get the current user loggedin using findById() of mongoose, but it always return null. I tried converting the id to mongoose.Types.ObjectId(string id), but i get the same result. How do i get the current user loggedin using findById(). Thanks in advance.
This is my controller
exports.createList = async (req, res, next) => {
const { error } = listValidation(req.body);
if (error) {
return res.status(404).send(error.details[0].message);
}
const list = new List({
title: req.body.title,
description: req.body.description,
createdDate: req.body.createdDate,
endDate: req.body.endDate,
creator: req.user._id,
});
try {
await list.save();
console.log("LIST CREATED");
console.log(req.user);
const user = await User.findById(mongoose.Types.ObjectId(req.user._id));
console.log(user);
user.lists.push(list);
await user.save();
console.log("LIST ADDED TO USER");
res
.status(201)
.json({ creator: { _id: user._id, username: user.username } });
} catch (error) {
res.status(400).send("An error occured");
}
};
This is the User model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema(
{
email: {
type: String,
required: true,
min: 6,
max: 255,
},
username: {
type: String,
required: true,
min: 6,
max: 255,
},
password: {
type: String,
required: true,
min: 6,
max: 1024,
},
lists: [
{
type: Schema.Types.ObjectId,
ref: "List",
},
],
},
{ timestamps: true }
);
module.exports = mongoose.model("User", userSchema);
Middleware to verified token and save user id to req.body
const jwt = require("jsonwebtoken");
module.exports = (req, res, next) => {
// Check if there is a token from req.header
const token = req.header("auth-token");
if (!token) {
return res.status(401).send("Access denied");
}
try {
const verified = jwt.verify(token, process.env.TOKEN_SECRET);
req.user = verified;
next();
} catch (error) {
res.status(400).send("Invalid token");
}
};
I want to use mongoose discriminator for my project to create a collection of users in which there is a document of owner which I want to implement using discriminators. But I am getting an error of
throw new Error('The 2nd parameter to mongoose.model() should be a ' +
^
Error: The 2nd parameter to mongoose.model() should be a schema or a POJO
at Mongoose.model (D:\Github\Food-Delivery-Website\node_modules\mongoose\lib\index.js:473:11)
at Object. (D:\Github\Food-Delivery-Website\models\Owner.js:21:27)
Code is given below:
// This file is models/User.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
const options = { discriminatorKey: 'kind' };
const UserSchema = new Schema(
{
userName: {
type: String,
required: true,
unique: true,
},
restOwned: {
// type: [Schema.Types.ObjectId],
type: Number,
},
},
options,
);
module.exports = mongoose.model('User', UserSchema);
Below is the next file
// This file is models/Owner.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
const User = require('./User');
const OwnerSchema = User.discriminator(
'Owner',
new Schema({
isOwner: {
type: Boolean,
required: true,
},
restName: {
type: String,
required: true,
},
}),
);
module.exports = mongoose.model('Owner', OwnerSchema);
Then I import these two files in userController.js
//This file is controllers/userController.js
const User = require('../models/User');
const Owner = require('../models/Owner');
exports.addUser = async (req, res) => {
try {
const newUser = new User({
userName: req.body.userName,
restOwned: req.body.restOwned,
});
const user = await newUser.save();
res.status(201).json({
status: 'Success',
user,
});
} catch (err) {
res.status(500).json({
status: 'failed',
message: 'Server Error: Failed Storing the Data.',
err,
});
}
};
exports.addOwner = async (req, res) => {
try {
const newOwner = new Owner({
isOwner: req.body.isOwner,
restName: req.body.restName,
});
const owner = await newOwner.save();
res.status(201).json({
status: 'Success',
owner,
});
} catch (err) {
res.status(500).json({
status: 'failed',
message: 'Server Error: Failed Storing the Data.',
err,
});
}
};
What am I doing wrong here?
enter image description here
The Model.discriminator() method returns a Model.
So you can directly export the discriminator and use it as the model
// This file is models/Owner.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
const User = require('./User');
//Directly export the discriminator and use it as the model
module.exports = User.discriminator(
'Owner',
new Schema({
isOwner: {
type: Boolean,
required: true,
},
restName: {
type: String,
required: true,
},
}),
);
//module.exports = mongoose.model('Owner', OwnerSchema);
i am try to inser user data into my database but data is not inserting and it is showing like User already exist with this email
How can solve this one ?
My code is below
i had tried with different email even though it is User already exist with this email and it is not inserting in the database.
server.js
require("dotenv").config();
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const port = process.env.PORT || 3500;
app.use(express.json());
//DB connection
mongoose
.connect(process.env.MONGO_URL)
.then(() => console.log("DB Connection Successful"))
.catch((err) => console.log(err));
//Routes
app.use("/api/auth/", require("./routes/auth"));
app.listen(port, () => {
console.log("Server is running on Port " + port);
});
user.js
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const userSchema = new mongoose.Schema(
{
firstName: { type: String, required: true, trim: true, min: 3, max: 30 },
lastName: { type: String, required: true, trim: true, min: 3, max: 30 },
userName: {
type: String,
required: true,
trim: true,
min: 3,
max: 30,
unique: true,
index: true,
lowercase: true,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
lowercase: true,
},
userPassword: { type: String, required: true },
role: { type: String, enum: ["user", "admin"], default: "admin" },
contactNumber: { type: String },
profilePicture: { type: String },
},
{ timestamps: true }
);
userSchema.virtual("password").set(function (password) {
this.userPassword = bcrypt.hashSync(password, 10);
});
userSchema.methods = {
authenticate: function (password) {
return bcrypt.compareSync(password, this.userPassword);
},
};
module.exports = mongoose.model("User", userSchema);
auth.js
const router = require("express").Router();
const User = require("../models/user");
router.post("/signin", (req, res) => {});
router.post("/register", async (req, res) => {
const user = User.findOne({ email: req.body.email });
if (!user) {
const newUser = new User(req.body);
await newUser.save();
res.status(201).json({
user: newUser,
});
} else {
res.status(400).json({
message: "User already exist with this email",
});
}
});
module.exports = router;
please find the attached images
Querying the database is an asynchronous function call.
Here at the auth.js, You're checking asynchronous if the user exits. const user = User.findOne({ email: req.body.email });
You should add await like that: const user = await User.findOne({ email: req.body.email });
Since, its asyncourouns Javascript doesn't wait for the answer and assings undefined to the user variable.
Therefore you end up at your else statement.
According to the error-trace the error occurs in the "validate" method, but as far as i see it my compare call is correct. I hope someone can explain to me why it happens anyways.
POST /user/register 500 23.312 ms - 2235
Error: data and hash arguments required
at Object.compare
at model.user_schema.methods.validate
The mongoose model:
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const salty = 10;
const user_schema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: false,
minlength: 3,
maxlength: 32
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
});
user_schema.pre('save', (next) => {
// if the password is not changed, there is no need to hash it again
if (!this.isModified('password')) return next();
// hash the user password
bcrypt.hash(this.password, salty, (err, hash) => {
if (err) return next(err);
this.password = hash;
return next();
});
});
user_schema.methods.validate = (claim, callback) => {
// compare the password to the existing hash from the database
bcrypt.compare(claim, this.password, (err, is_match) => {
if (err) return callback(err);
return callback(null, is_match);
});
}
module.exports = mongoose.model('user', user_schema);
The router with the create call:
router.post('/register', (req, res, next) => {
let new_user = {
name: req.body.name,
email: req.body.email,
password: req.body.password
};
user_model.create(new_user, (err, user) => {
if (err) return next(err);
res.send(user);
});
});
I have a database for my login purposes contains loginid, username, password etc. How do I define that my usernames, loginids and passwords are unique in the MongoDB? That means no duplicates are allowed to be created. Here is some code I use:
app.post('/api/register', async function (req, res){
try {
const hashedPassword = await bcrypt.hash(req.body.password, 10);
console.log(hashedPassword);
console.log(await bcrypt.compare('testtest',hashedPassword));
var user = new User({ loginId: req.body.id, firstname: req.body.username, password: hashedPassword });
user.save(function (err, User) {
if (err) return console.error(err);
console.log("Saved successfully");
});
jwt2.sign({user}, 'secrethere', { expiresIn: '15min'}, (err, token) =>{
res.json({
token
});
});
} catch (err) {
res.status(500).send()
console.log(err);
}
});
My user.js:
const mongoose = require('mongoose');
const userSchema = mongoose.Schema({
loginId: String,
firstname: String,
lastname: String,
eMail: String,
password: String,
active: Boolean
});
module.exports = mongoose.model("User", userSchema);
You can use unique: true option in mongoose schema definition.This option creates an unique index on the field.
Making password field unique may not a good idea.
const mongoose = require("mongoose");
const userSchema = mongoose.Schema({
username: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
firstname: String,
lastname: String,
active: Boolean
});
module.exports = mongoose.model("User", userSchema);
This will cause an error like this when a duplicate loginId is being tried to insert:
UnhandledPromiseRejectionWarning: MongoError: E11000 duplicate key
error collection: ....
This unique: true option is supposed to create an unique index.
But it does not create, you can manually create using the following script:
db.users.createIndex( { "email": 1 }, { unique: true } );
db.users.createIndex( { "username": 1 }, { unique: true } );
I also refactored your register route like this:
app.post("/api/register", async (req, res) => {
const { username, email, password, firstname, lastname } = req.body;
let user = new User({ username, email, password, firstname, lastname });
try {
user.password = await bcrypt.hash(user.password, 10);
user = await user.save();
const token = jwt.sign(
{
_id: user._id,
username: user.username,
email: user.email,
firstname: user.firstname,
lastname: user.lastname
},
"secrethere",
{ expiresIn: "15min" }
);
res.json({
token
});
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});