I am trying to register a user and save the user to MongoDB. I am creating the user using nodejs readline module. But when I am trying to save it to the mongodb it is not working. Nor does it is returning any error.
Here's the code
const { Admin, validate } = require('../models/admin');
const mongoose = require('mongoose');
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const print_error = '\x1b[31m%s\x1b[0m';
const print_success = '\x1b[32m%s\x1b[0m';
function createUser() {
rl.question('Please Enter Username : ', (username) => {
rl.question('Please Enter a Password : ', async(password) => {
const adminObject = {
username,
password
};
const { error } = validate(adminObject);
if (error) {
rl.close()
rl.removeAllListeners()
return console.log(print_error, error.details[0].message);
}
let admin = await new Admin({
username: username,
password: password
});
console.log(admin);
const result = await admin.save(function(err,res){
if(err){
console.log('err',err);
return console.log('err',err);
}
else return console.log('res', res);
}); // save is not working
console.log(print_success, result);
rl.close(process.exit(1)); // close the process after done saving
});
});
}
createUser();
Admin Model
const mongoose = require('mongoose');
const Joi = require('joi');
const Admin = new mongoose.model('Admin', new mongoose.Schema({
username: {
type: String,
required: true,
minlength: 1,
maxlength: 10,
unique: true
},
password: {
type: String,
required: true,
minlength:3,
maxlength: 1024
}
}));
function validateAdmin(admin){
const schema = {
username: Joi.string().min(1).required(),
password: Joi.string().min(3).required()
};
return Joi.validate(admin, schema);
}
exports.Admin = Admin;
exports.validate = validateAdmin;
P.S - I've connected to the mongodb, the connection is successful.
I don't know why you're use async/await and then you use function in your save.
You can change your createUser function with this code below:
function createUser() {
rl.question('Please Enter Username : ', (username) => {
rl.question('Please Enter a Password : ', async(password) => {
const { error } = validate({ username, password });
if (error) {
rl.close()
rl.removeAllListeners()
return console.log(print_error, error.details[0].message);
}
let admin = new Admin({username, password });
try {
const result = await admin.save();
console.log(print_success, result);
rl.close(process.exit(1));
} catch(ex) {
console.log(ex.message);
}
});
});
}
If you've any problem, then let me know in the comment below.
Updated: After test your code, you have no connection in your createUser.js.
I've been add this connection below in above of your createUser() and it's working:
mongoose.connect('mongodb://localhost:27017/url-shortener');
Please, make sure you've add a connection to your mongodb.
I hope it can help you.
Related
I created an API for following and followers user for Social Media Application, while request from postman getting empty object: {} But it seems to me to be correct.
Model:
const mongoose = require("mongoose");
const UserSchema = mongoose.Schema({
username: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
firstname: {
type: String,
required: true,
},
lastname: {
type: String,
required: true,
},
isAdmin: {
type: Boolean,
default: false,
},
profilePicture: String,
coverPicture: String,
about: String,
livesin: String,
workAt: String,
relationship: String,
followers: [],
following: []
},{
timestamps:true
}
);
const UserModel = mongoose.model("Users", UserSchema);
module.exports = UserModel;
UserControler:
const UserModel = require("../Models/Usermodel");
const bcrypt = require("bcryptjs");
const followUser = async (req, res) => {
const id = req.params.id.trim();
const { currentUserId } = req.body;
if (currentUserId === id) {
res.status(403).send("Action forbiden");
} else {
try {
const followUser = await UserModel.findById(id);
const followingUser = await UserModel.findById(currentUserId);
if (!followUser.followers.includes(currentUserId)) {
await followUser.updateOne({ $push: { followers: currentUserId } });
await followingUser.updateOne({ $push: { following: id } });
res.status(200).send({message:"User Followed"});
} else {
res.status(403).send("User alredy followed by you!");
}
} catch (error) {
res.status(500).send(error);
}
}
};
module.exports = { getUser, updateUser, userDelete, followUser };
UserRoute:
const express = require("express");
const {getUser,updateUser, userDelete, followUser} = require("../Controller/userControler");
const router = express.Router()
router.get("/:id",getUser)
router.put("/:id",updateUser)
router.delete("/:id", userDelete)
router.put("/:id/follow", followUser)
module.exports=router;
index.js:
app.use("/user",UserRoute)
Here is the complete details regarding the error, let me know what happens in the code, thank you.
i assume that you have all the other functions other than followUser in your controller.js
The thing is that you must first specify the field name on the basis of which you want to update the document.
Here is what you need to do;
const UserModel = require("../Models/Usermodel");
const bcrypt = require("bcryptjs");
const mongoose = require("mongoose");//updated line
const followUser = async (req, res) => {
const id = req.params.id.trim();
const { currentUserId } = req.body;
if (currentUserId === id) {
res.status(403).send("Action forbiden");
} else {
try {
const followUser = await UserModel.findById({_id: mongoose.Types.ObjectId(id)});
const followingUser = await UserModel.findById({_id: mongoose.Types.ObjectId(currentUserId)});
if (!followUser.followers.includes(currentUserId)) {
await followUser.updateOne({_id: mongoose.Types.ObjectId(*id of the user you want to update*)},{ $push: { followers: currentUserId } });
await followingUser.updateOne({_id: mongoose.Types.ObjectId(*id of the user you want to update*)}{ $push: { following: id } });
res.status(200).send({message:"User Followed"});
} else {
res.status(403).send("User alredy followed by you!");
}
} catch (error) {
res.status(500).send(error);
}
}
};
module.exports = { getUser, updateUser, userDelete, followUser };
And while hitting the api pls make sure that your route should be
localhost:port-number/user/12345789/follow
and also make sure that the API type in postman must be same as in the backend e.g; PUT
please try findByIdAndUpdate query insted of using updateOne
I use Sequelize to work with the database.
In my project, I encountered code duplication, and decided to study the repository design pattern, which will separate the work with the database and data output from the business logic. Having studied the information on the Internet, I decided to consolidate the material and check with more experienced programmers. I use the repository pattern correctly?
controller/user.controller.js
const userService = require('../services/user.service');
exports.userCreate = async (req, res, next) => {
try {
const user = await userService.userCreate(req.body);
return res.status(201).json(user);
} catch (e) {
return next(e);
}
}
services/user.service.js
const ApiError = require('../utils/error');
const userRepo = require('../repositories/user.repository');
exports.userCreate = async (data) => {
if (!data) throw ApiError.badRequest('Bad');
const { login } = data;
if (!login) throw ApiError.badRequest('Bad');
const password = 'hash';
const user = await userRepo.userCreate({login, password});
return user;
}
repositories/user.repository.js
const User = require('../models/User');
exports.userCreate = async (data) => {
const { login, passowrd } = data;
const user = await User.create({login, password});
return {
login: user.login,
}
}
models/User.js
const { sequelize, Sequelize } = require('../config/db');
const User = sequelize.define('users', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true,
},
login: {
type: Sequelize.STRING,
allowNull: false,
},
password: {
type: Sequelize.STRING,
allowNull: false,
}
});
module.exports = User;
Your User model is fine, but the structure of the service seems a little weird. if all three of the functions userCreates are in separate files I'd recommend you combine them and rename services to Controllers, as services are usually used on the client side of things.
services/user.service.js
const User = require('../models/User')
// const userRepo = require('../repositories/user.repository') Not sure what this does
const ApiError = require('../utils/error')
module.exports = {
async createUser (req, res) {
try {
if (!req.body) throw ApiError.badRequest('Bad')
const { login } = req.body
if (!login) throw ApiError.badRequest('Bad')
const password = 'hash'
const user = await User.create({ login, password })
res.stauts(201).json(user.login)
} catch (err) {
console.log(err)
res.staus(500).send({
error: err
})
// return next(err)
}
}
}
I want to update user data without entering all the fields like for example if I only enter name then only name gets updated other values remain same. But, when I tried doing that my password validation is showing error, and also saying isAdmin is required.
here is my thunder Client Screen:
To check whether I am getting all user data I consollLoged and I am getting every field:
Here is my code:
userModel.js
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const userSchema = mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
match: [
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
"Please enter a valid email address",
],
},
password: {
type: String,
required: true,
match: [
/^(?=.*[A-Za-z])(?=.*\d)(?=.*[#$!%*#?&])[A-Za-z\d#$!%*#?&]{8,}$/,
"Password must contain minimum eight characters, atleast one letter, one number & one speccial character ",
],
},
isAdmin: {
type: Boolean,
required: true,
default: false,
},
},
{
timestamps: true,
}
);
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
// We are encrypting data before saving it
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
});
const User = mongoose.model("User", userSchema);
module.exports = User;
userController.js
// #description: Update user
// #route: PUT /api/users/:id
// #access: Private/Admin
exports.updateUser = async (req, res, next) => {
try {
const user = await User.findById(req.params.id);
if (user) {
console.log(`USER: ${user}`);
user.name = req.body.name || user.name;
user.email = req.body.email || user.email;
user.isAdmin = req.body.isAdmin;
const updatedUser = await user.save();
res.json({
_id: updatedUser._id,
name: updatedUser.name,
email: updatedUser.email,
isAdmin: updatedUser.isAdmin,
});
} else {
const error = new Error("Sorry, user Not Found");
error.status = 404;
next(error);
}
} catch (error) {
next(error);
}
};
UPDATE:
I tried commenting match for password in my userModel.js
password: {
type: String,
required: true,
// match: [
// /^(?=.*[A-Za-z])(?=.*\d)(?=.*[#$!%*#?&])[A-Za-z\d#$!%*#?&]{8,}$/,
// "Password must contain minimum eight characters, at-least one letter, one number & one special character ",
// ],
},
and I am able to update the values.
What can I do so that it works with match as well.
The problem is in pre-save hook:
// We are encrypting data before saving it
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
});
You call next() and the code goes further messing with this.password etc.
Just return after next()
// We are encrypting data before saving it
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
return
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
});
You can even simplify to:
// We are encrypting data before saving it
userSchema.pre("save", async function (next) {
if (this.isModified("password")) {
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
}
next()
});
Have been trying to create a password hash in my nodejs code
But it not working and not showing any error message for me to debug.
And my user is not creating also.
I dont know if there is a better way to do it.
This is my file which is responsible for the code...Model/User.js
const Promise = require('bluebird')
const bcrypt = Promise.promisifyAll(require('bcrypt-nodejs'))
function hashPassword (user) {
const SALT_FACTOR = 8
if (!user.changed('password')) {
return;
}
return bcrypt
.genSaltSyncAsync(SALT_FACTOR)
.then(salt => bcrypt.hashAsync(user.password, salt, null))
.then(hash => {
user.setDataValue('password', hash)
})}
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
}, {
hooks: {
beforeCreate: hashPassword,
beforeUpdate: hashPassword,
beforeSave: hashPassword
}
})
User.prototype.comparePassword = function (password) {
return bcrypt.compareAsync(password, this.password)
}
return User }
Does the following snippet help in any way?
const bcrypt = require('bcryptjs');
const userAbc = {
email: 'user#user.com',
password: '1234'
}
async function hashPassword(user) {
try {
const hashedPassword = await bcrypt.hash(user.password, 12);
user.password = hashedPassword;
console.log(user);
} catch (err) {
console.log(err);
}
}
hashPassword(userAbc);
I did change the bcrypt-nodejs to bcryptjs then replace genSaltSyncAsync to genSaltSync and everyother Async to Sync and it worked.
I'm teaching myself Mongodb. At first, I ran npm install --save mongoose uuid in Terminal to start things off. The goal of my program is to store a user in the database.
In Terminal, after running node index.js I want it to say:
About to save!
Saved!
But what I'm seeing in Terminal is (below):
Here's index.js
var mongoose = require('mongoose');
var uuid = require('uuid');
var Schema = mongoose.Schema;
/* New code from suggested website in error */
var promise = mongoose.connect('mongodb://localhost:testMongo/testMongo', {
useMongoClient: true,
});
promise.then(function(db) {
db.model();
connection.openUri('mongodb://localhost:testMongo/testMongo', { /* options */ });
var userSchema = new Schema({
email: {
type: String,
unique: true
},
password: {type: String},
todos: [
{
text: {type: String}
}
]
});
userSchema.pre('save', function(next) {
console.log("About to save!");
var user = this;
user.password = uuid.v4();
next();
});
var User = mongoose.model('user', userSchema);
var email = 'test#test.com';
// var user = new User({
// email: email
// });
//
// user.save(function(err) {
// if(err) {
// return console.log(err);
// } else {
// return console.log("User was saved!");
// }
// })
//
// console.log("Outside of callback!");
var text = "This is a todo.";
User.findOne({email: email}, function(user, err) {
if(err) {
return console.log(err);
}
if(!user) {
return console.log("Couldn't find user!");
}
var count = user.todos.push({
text: text
});
console.log(count);
user.save(function(err){
if(err) {
console.log(err);
} else {
console.log("Saved!");
}
});
});
Error in Terminal:
(node:14312) DeprecationWarning: `open()` is deprecated in mongoose >= 4.11.0, use `openUri()` instead, or set the `useMongoClient` option if using `connect()` or `createConnection()`. See http://mongoosejs.com/docs/connections.html#use-mongo-client
{ _id: 595fe7c14a9810330c75aacc,
password: '297d5907-d9d7-49ef-800c-97a56aa395f7',
email: 'test#test.com',
__v: 0,
todos: [] }
That is not an error. It clearly says it's a warning: DeprecationWarning.
Also the message gives you a link to resolve the warning: http://mongoosejs.com/docs/connections.html#use-mongo-client