Checking whether a document present in mongodb using mongoose - node.js

I am trying to create a nodejs application using mongodb as database. I need to check whether a username exist in mongodb or not. If username present, it will output "username not available", else will list all the user details with that username.
var userSchema = require('../schemas/user');
exports.collect = function(req,res) {
userSchema.find({ username: "bob" }).exec(function(err,display) {
if(err){
console.log(err);
}
else
{
if(display=='[]'){
res.send("username not available");
}
else{
res.send(display)
}
}
});
};
Is there any alternative or simple way for performing this operation?

I would decouple the whole logic from the controller if you ask me, but I'm not going to lecture you on that. I would use findOne as that will find just one record. If the user is not available, you will know that this username is not available. Don't forget that even when an error occurs, you still want to output "some" data, as you don't want the client to wait until it times out.
var userSchema = require('../schemas/user');
exports.collect = function(req,res) {
userSchema.findOne({username: "bob"}).exec(function(err, user) {
if (err) {
console.log(err);
// Handle the error properly here, we should not continue!
return res.sendStatus(500);
}
if (!user) {
return res.send("username not available");
}
// Don't know what you want to do with it, I just display it like this
return res.json(user);
});
};

Related

I want to check another field When I get dublicate key error for email (unique) in mongodb findoneandupdate

User.findOneAndUpdate({ _id: userFindByid }, {
$set: {
"email": req.body.email,
"username": req.body.username,
"phone_number": req.body.phone_number,
"address": req.body.address,
"isBenefactor": req.body.isBenefactor,
"location": req.body.location
}
}, { runValidators: true, context: 'query' }, (err, doc) => {
if (err) {
// if request email has already exist in db I want to check that emails isDeleted field in here . if isDeleted is true I want to update .
return res.status(500).json({ message: err.message });
}
else {
return res.status(200).json({ message: 'Your account was updated' });
}
})
//
Let me explain scenario clearly,
I registered with an email address(first#gmail.com) then I deleted my account =>(first#gmail.com)=>isDeleted=true
After that I again registered with another email address(second#gmail.com)=>isDeleted=false
Now I want to update my second email address with first one I will get an unique key error because (first#gmail.com) is in mydb ,but I have to da update process because (first#gmail.com)=>IsDelete=true
If I use { 'email': req.body.email, 'isDeleted': true} I can not update (second#gmail.com)=>isDeleted=false
I can fix the problem by using too much if statements , but I dont want to use if statements too much. I am looking for best practice for that problem.
I hope I could explain
Here is my code block , can someone help me ?
THIS ANSWER ASSUMES YOU ARE USING MONGOOSE!
One way you can do is instead of using findOneAndUpdate you can use .save this way you can issue a hook on mongoose.
For example, you would do User.save(...) then you go to your schema code and you add the following (assuming your schema name is UserSchema)
UserSchema.post('save', function(error, doc, next) {
// Error code 11000 means this is a duplicate
if (error.name === 'MongoError' && error.code === 11000) {
// So instead of throwing an error you would do anything you want
// Such as look for the other record and delete it, update its isDelete
// field, remove email, etc... really is up to you
}
next()
});
EDIT: Of course before User.save(...) you need to find the user!
For example,
User.findOne({_id:1}, function(err, doc){
// Update doc values
// Finally do doc.save(...)
})
You can make it look much better by using the async library and using async.waterfall
EDIT2: Okay so now that I understand your requirement better, here is your best solution in my opinion.
Find the user you want to update
Change email
Save
On the other side, you need to have a hook (unfortunately its poorly documented, you have to do your own digging but here is a link to mongoose documentation)
Here is how this will work
1. Hook a pre save (before actually saving execute specific block of code)
2. The block of code will only execute when the email is modified (we dont want to execute it everytime, its just a waste of resources)
3. The block of code will use deleteOne and delete the user matching that email
NOTE: For best performance make sure to index the email and make it unique!
I have created the full (similar to what you want) project with the code on here
But if you wish here are also some snippet
// This will run before saving the object
UserSchema.pre('save', function (next) {
let user = this
// Make sure to run only when email is modified
if(user.isModified('email')) {
// IF the email was modified, then attempt to delete a record with this email (if there is one, then it will be deleted otherwise it will just continue)
this.constructor.deleteOne({email:this.email, isDeleted:true}, (err) => {
err ? next(err) : next()
})
} else {
next()
}
})
// Code to save/update the user
User.findOne({_id:"1"}, function(err, user) {
if (err) {
throw err
} else {
if (user) {
user.email = "test2#test.com"
user.save(err => {
err ? console.log(err) : console.log("Success!")
})
} else {
console.log("User was not found!")
}
}
})
Good luck!

Mongoose not saving document completely

I am trying to save data to my mongo db using mongoose. But unfortunately I am not able to save it completely. However it creates a data array but defaults like company name etc. are not saving. However these values are not available in requested body
I am using:
var seller = new sellers(req.body);
seller.save(function (err) {
if (err) {
return res.status(500).send('An user with this email id or mobile number already exist');
}
res.status(200).send('You have successfully registered');
})
In this case you could use a pre save hook to set an object as the default in your array:
userSchema.pre('save', function(next) {
if (this.data.length == 0) {
var default = {
fieldName: 'Company Name',
fieldValue: 'No Information Provided',
// etc.
};
this.data.push(default);
}
next();
});

Mongoose Pre Command not working as Expected

Hi I am New to Mongoose And trying to use pre command to Convert a given password in String to Hash values before saving it in the database. I am not Getting any Syntax error but my password is not getting converted into Hash IDS.
My Controller Code is as follows:
User.save(req.body,function(err,data){
if (err) {
res.json({
sucess:false,
exception:err
});
}
else{
res.json({
sucess:true,
User:data
});
}
});
User.pre('save',function(next){
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt){
if(err){
return res.json({
success:false,
exception:err
});
}
bcrypt.hash(password, salt, function(err, hash) {
if(err){
return res.json({
success:false,
exception:err
});
}
password=hash;
});
});
next();
});
Using Node inspector I found out that command line is not entering the User.pre .So Can somebody let me know where I am making a mistake.
There's various things wrong with your code, the main part being that hooks should be attached to the schema and not the model, which seems to be what you're doing.
Also, it looks like you're trying to add a pre-save hook for every request, which is not how hooks are supposed to work: they should be declared just once, on the schema (as said above) and before you create the model.
The order should be similar to this:
var UserSchema = new mongoose.Schema(...);
UserSchema.pre('save', ...);
var User = mongoose.Model(UserSchema);
This means that you can't send an error response from your pre-save hook, as you're trying to do now, but you don't really want that anyway IMO (you should keep your Mongoose schema/models separated from your Express route handlers). Instead, catch any errors that are thrown during .save() and handle them there.
To give an idea on what a proper hook might look like, here's an example (I took a guess as to your User schema so it may be using the wrong field names):
UserSchema.pre('save', function(next) {
var document = this;
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
bcrypt.hash(document.password, salt, function(err, hash) {
if (err) return next(err);
document.password = hash;
next();
});
});
});

Mongoose Returned Model can't be updated

I'm pretty new to Mongoose/Mongo and node.js, so I suspect this is just a misunderstanding on my side, but...
The code sample below is the smallest failing example, not specifically my use case.
var User = app.db.model('User');
User.find({email: 'm8#test.com'}, function (err, models) {
models[0].update(function(err, mod) {
console.log(err.message)
});
});
This results in the following error: After applying the update to the document {_id: ObjectId('54647402cb955748153ea782') , ...}, the (immutable) field '_id' was found to have been altered to _id: ObjectId('546d9e0e539ed9ec102348f9')
Why is this happening? I would have thought calling update on the model returned from the initial find would have been fine.
Please note: in my use case there are things happening in between the find and the update. Specifically, I'm doing something similar to:
model.property.push(objectId)
Which I then want to commit via the update.
I'm sure this is a straight-forward issue, but I can't see anywhere in the docs I may be getting it wrong.
All help appreciated.
UPDATE:
What I actually needed to do was:
var User = app.db.model('User');
User.find({email: 'm8#test.com'}, function (err, models) {
models[0].save(function(err, mod) {
console.log(err.message)
});
});
Using 'save' rather than 'update'
I don't know if I understood
Find and Update ( for example using express )
var email = req.params.email;
User.find({email:email}, req.body, function(err,user){
if(err){
throw err;
}
//you do stuff like this
var obj = {
password:'new pass',
username:'username'
}
//use save if you want validate
User.update(user[0],obj,function(err, mod) {
console.log(err)
});
});
Only Update: ( for example using express )
User.update({email:email}, req.body, {}, function(err,user){
if(err){
throw err;
}
res.send(200, {
message : 'User updated ' + user
});
});
Remember that:
A model is a compiled version of the schema.
I hope this can help you

Pre-populating documents using Mongoose + Express

I am new to Node+Mongoose, and am currently in the process of creating an API using KeystoneJS. I've managed to populate all posts with the author's email and name. My question is, is there a way to populate the post with author everytime, possibly with some middlewear, without having to rewrite it in each method where I retrieve posts? My goal is to not have multiple instances of populate('author', 'email name') scattered throughout the code. For instance, in the future, I'd like to include the author's profile photo url as well, and I'd prefer to be able to make that change in a single place, that will then be reflected in every place that I retrieve posts.
Current implementation:
Post.model.find().populate('author', 'email name').exec(function (err, posts) {
if (!err) {
return res.json(posts);
} else {
return res.status(500).send("Error:<br><br>" + JSON.stringify(err));
}
});
Post.model.findById(req.params.id).populate('author', 'email name').exec(function (err, post) {
if(!err) {
if (post) {
return res.json(post);
} else {
return res.json({ error: 'Not found' });
}
} else {
return res.status(500).send("Error:<br><br>" + JSON.stringify(err));
}
});
You can create model using statics. This is example of methods for schema
PostSchema.statics = {
getAll: function(cb) {
return this
.find()
.populate('author', 'email name')
.exec(cb);
}
}
You still should use "populate", but it will be in schema file, so you will not care about it in future

Resources