I created this web API using mongoose.
POST and GET work fine, but mongoose seems to work like post, so instead of updating previous data, it creates a new one with a unique ID.
Here is my code:
router.put("/update", (req, res, next) => {
const formInput = new Form({
// _id: '5e20275e2d0f182dd4ba320a',
firstname: req.body.firstname,
lastname: req.body.lastname,
});
Form.findByIdAndUpdate({_id: '5e20275e2d0f182dd4ba320a'}, formInput, {new: true}, (err, result) => {
if (err) return res.status(500).send(err);
return res.send(result);
});
});
Mongoose Schema
var formSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
firstname: {
type: String,
// required: true
},
lastname: {
type: String,
// required: true
},
},
{
collection: 'formsInput'
});
module.exports = mongoose.model('Form', formSchema);
You don't need to create a new Form instance for updating, you can simply do
router.put("/update", (req, res, next) => {
Form.findByIdAndUpdate({_id: '5e20275e2d0f182dd4ba320a'}, {...req.body}, {new: true}, (err, result) => {
if (err) return res.status(500).send(err);
return res.send(result);
});
});
The formInput parameter to findByIdAndUpdate should be a plain object, not a Form instance:
const formInput = {
firstname: req.body.firstname,
lastname: req.body.lastname,
};
Related
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");
}
});
I'm new to MongoDB/Mongoose and trying to figure out how to map relationships between Schema. I don't think issue is with .populate(). At creation of new user and clients, I do not see the relationship reflected in collection
User (login via local/social) has many Clients.
A set of Clients belong to 1 User
Is this the correct way to declare foreign key? {type: Schema.Types.ObjectId, ref: 'Client'}
Should both Schema have the each other's foreign key to relate to one another?
Is there any additional code required when creating User/Client in order for the data from foreign key to show up? I read something about populate()
User
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
local: {
id: String,
email: String,
password: String,
name: String,
mobile: String,
clients: {type: Schema.Types.ObjectId, ref: 'Client'}
},
google: {
id: String,
token: String,
email: String,
name: String,
clients: {type: Schema.Types.ObjectId, ref: 'Client'}
}
});
module.exports = mongoose.model('User', userSchema);
Client
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var clientSchema = new Schema({
id: String,
firstname: String,
lastname: String,
mobile: String,
user: {type: Schema.Types.ObjectId, ref: 'User'}
});
module.exports = mongoose.model('Client', clientSchema);
Create User
app.post("/api/user", function (req, res) {
const user = req.body;
console.log(user);
User.findOne({ 'local.email': user.email },
function (err, result) {
if (err) {
console.log(err);
handleError(err, res);
return;
}
if (result) {
res.status(500).send("Email already exists in database");
} else {
var newUser = new User();
newUser.local.password = generateHash(user.password);
newUser.local.email = user.email;
newUser.local.name = user.name;
newUser.local.mobile = user.mobile;
newUser.save(function (err, result) {
res.status(201).send("User added to database");
});
}
});
});
Create Client
app.post("/api/client", function (req, res) {
const client = req.body;
console.log(client);
Client.findOne({
$and: [
{ firstname: client.firstname },
{ lastname: client.lastname }
]
},
function (err, result) {
if (err) {
console.log(err);
handleError(err, res);
return;
}
if (result) {
res.status(500).send({msg:"Client already exists in database"});
} else {
var newClient = new Client();
newClient.firstname = client.firstname;
newClient.lastname = client.lastname;
newClient.mobile = client.mobile;
newClient.save(function (err, result) {
res.status(201).send("Client added to database");
});
}
});
});
I am getting the correct data for friendRequests which is getting a user ID and throwing it in the friendRequest field of my mongoose file. When I add $push to add the data into the friendRequest array in the route file, it actually does not insert it and gives me back the err function I created.
Here is my route file:
exports.addContactPost = function(req, res, err) {
User.findByIdAndUpdate(req.signedCookies.userid, {
$push: {friendRequest: req.body.friendRequest}
}, function(err) {
if(err) {
console.log("post2");
return console.log('error');
}
else {
console.log('postsuccess');
res.json({response: true});
}
});
};
Here is the mongoose file:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt-nodejs'),
SALT_WORK_FACTOR = 10;
var UserSchema = new Schema({
email: { type: String, required: true, lowercase:true, index: { unique: true } },
password: { type: String, required: true },
firstName: {type: String, required: true},
lastName: {type: String, required: true},
phone: {type: Number, required: true},
birthday: {type: Date, required: true},
friendRequest: {type: Array},
friend: {type: Array}
});
UserSchema.pre('save', function(next) {
var user = this;
console.log("email exists");
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password along with our new salt
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
UserSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', UserSchema);
So the document that mongo finds matching the provided userId does not have an array as its friendRequest property. Look at that specific document by ID in mongo shell and fix it so that friendRequest is an array.
I am unsure as to why I am getting an error for POST-ing a form. I am using mongoose to connect to mongodb and using Jade as my view engine. I am trying to POST an update and not a new account into the db, and using a cookie to pull the user's info. So it is the Edit User Profile page. Everything works on the Jade file and looks right, just when I hit the submit button it goes to a:
Cannot POST /editUserProfile
My mongoose User file:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt-nodejs'),
SALT_WORK_FACTOR = 10;
var UserSchema = new Schema({
email: { type: String, required: true, lowercase:true, index: { unique: true } },
password: { type: String, required: true },
firstName: {type: String, required: true},
lastName: {type: String, required: true},
phone: {type: Number, required: true},
birthday: {type: Date, required: true}
});
UserSchema.pre('save', function(next) {
var user = this;
console.log("email exists");
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password along with our new salt
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
UserSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', UserSchema);
My route file:
exports.editUserProfile = function(req, res) {
User.findById(req.signedCookies.userid, function(err,user) {
if(err) {
res.send(err);
} else {
console.log(JSON.stringify(user));
res.render('editUserProfile', {title: 'Weblio',
ufirstName: user.firstName,
ulastName: user.lastName,
uemail: user.email,
uphone: user.phone,
ubirthday: user.birthday
});
//, user: user.firstName, - taken out after title
}
});
};
exports.editUserProfilePost = function(req, res) {
var updateUser = new User ({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
phone: req.body.phone,
birthday: new Date(req.body.birthday)
});
updateUser.save(function(err){
console.log("here 3");
if(!err) {
console.log("here3a");
res.render('userProfile', {title: 'Weblio'});
} else {
console.log("here 1a");
(new Error('Incorrect POST'));
return res.render('editUserProfileError', {title: 'Weblio'});
}
});
};
Jade file:
extends layout
block content
div.centerContent
form.validateForm(method="POST", action="/editUserProfile")
legend Edit Profile
input(type="text", name="firstName", maxlength="20", placeholder=ufirstName, value=ufirstName)
br
input(type="text", name="lastName", maxlength="20", placeholder=ulastName, value=ulastName)
br
input(type="email", name="email", maxlength="20", placeholder=uemail, value=uemail)
br
input(type="number", name="phone", maxlength="20", placeholder=uphone, value=uphone)
br
input(type="date", name="birthday", placeholder=ubirthday, value=ubirthday)
br
input.btn.btn-primary(type="submit", name="Update", value="Save")
a(href="/userProfile")
button.btn(type="button") Cancel
This is my app.js file: I have a bunch of other things in there but the Register part is getting POST-ed so I don't think the app.js has any problems.
app.get('/editUserProfile', user.editUserProfile);
app.post('/editUserProfile', user.editUserProfilePost);
Updated:
exports.editUserProfilePost = function(req, res, err) {
User.findByIdAndUpdate(req.signedCookies.userid,{
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
phone: req.body.phone,
birthday: new Date(req.body.birthday)
}, function(err) {
if(!err) {
console.log("post2");
res.render('userProfile', {title: 'Weblio'});
} else {
console.log("post3");
(new Error('Incorrect POST'));
return res.render('editUserProfileError', {title: 'Weblio'});
}
});
};