Keeping track of WHERE clause value that don't yield result - node.js

I have a function that checks whether a given email address exists in a "user" table. I use sequelize's findone method to do that. This method is simple enough for finding particular value in the table. But, what I like to do is to keep track of those email addresses that aren't in that table. I'm not sure if there is any event that I can intercept for that matter. But my google attempts didn't yield any solution. So any help is appreciated. This is my code
function IsUserExist(email, callback)
{
var userModel = sequelize.define('user', {
email_address: Sequelize.STRING(255)
},
{ timestamps: false,
freezeTableName: true
});
userModel.findOne({
where: { email_address: emailAddress }
})
.then(function(users){
callback();
})
.catch(function(err){
console.log("Error while accessing user table");
})
.done();
}

So, I finally figure out how to do it. Basically, the parameter of "then" method is null if findOne does not yield any result. So, in my case "users" is null if a query does not return any result. If it does, "users" contains a record.

Related

Looking up a mongoDB database

so I have implemented a register page that sends the inputs into a mongoDB atlas. However, I am trying to implement a new page where users are able to login. I am having trouble trying to find the specific key: value pair in order to check my inputs.
My mondoDB atlas shows the following:
_id: 62da20a99df697486c4b12cc
username: "hello"
password: "hello"
__v: 0
My function for logging in is the below:
exports.login = async (req, res) => {
if (await User.find({ username: req.body.username })) {
console.log("do smth");
}}
For now, lets just ignore the console.log() as I just want to see whether its going through or not. It's always evaluating to true and I don't know why. I can type any input and it always goes through but I'm not sure why its always evaluating to true so I know for sure I'm not looking up at the database correctly.
The
User.find()
where
User
is the name of the variable I defined when requiring the file I defined my schema. Any help would be appreciated in terms of how I should look up a key which in this case is username and I want to look up the req.params.username to see if that actually exists in my database.
Updated CODE
exports.login = async (req, res) => {
if (
User.findOne({ username: req.body.username }, function (err, user) {
console.log(user);
})
) {
res.send("YES");
} else {
res.send("NO");
}
If the input is in the database, it will log the user which in this case is
{
_id: new ObjectId("62daeb740c2c6e2b61325151"),
username: '123',
password: '123',
__v: 0
}
However, if its not in the database, it will log null but the if statement still evaluates to true.
User.find returns an array, which may be empty or not, but is never false in the Javascript sense. By contrast User.findOne returns an object, or null if nothing is found, and null does not satisfy the if condition. Probably that's what you want.
If User.findOne returns a Query, you can try invoking it with a callback function:
User.findOne({username: req.body.username}, function(err, user) {
if (err)
console.error(err);
else if (user) {
console.log("do smth");
}
});

Create document using Mongoose.js with Projection and Unique validation

Is there any way to have the same options as findOneAndUpdate() when creating a document. I realize I can set upsert: true but I am looking to throw an error if the document already exist.
So say I have Courses in a database and when to insert a new one. If I use .create() I get no ability to project, or use lean. :dis
If I use findOneAndUpdate then it does not throw an Error for a document with a duplicate field as it is updating as existing document which I do not want to do.
Basically I would like the abilities that come with .findOneAndUpdate() but I want it to throw an error if it finds a document, since I am searching for it based off the field which I wish to be unique
By looking to your problem , you can try the following approach
function updateUser(user,cb){
UserModel.find({name : user.name}, function (err, docs) {
if (docs.length){
cb('Name exists already',null);
}else{
user.save(function (err, returned) {
var leanObject = returned.toObject();
assert.equal(leanObject.schema, null);
});
}
});
}
So , in the above code , you find for the document and and if we get the result non-empty , we can consider it as an error otherwise we can save that document as new entry .
So to accomplish the desired goals I have done the below. Where I use a query condition that I know will fail. That way I am forcing the upsert and get the benefits of the options.
async addCourse(input, projection = {}) {
const { name } = input;
const conditions = { _id: mongoose.Types.ObjectId() };
const newCourse = await this.model.findOneAndUpdate(conditions, input, {
upsert: true,
new: true,
lean: true,
projection,
runValidators: true,
context: 'query',
setDefaultsOnInsert: true,
});
return newCourse;
}

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!

How to update some data based on array value in Mongoose?

I'd like to update some data in Mongoose by using array value that I've find before.
Company.findById(id_company,function(err, company) {
if(err){
console.log(err);
return res.status(500).send({message: "Error, check the console. (Update Company)"});
}
const Students = company.students;
User.find({'_id':{"$in" : Students}},function(err, users) {
console.log(Students);
// WANTED QUERY : Update company = null from Users where _id = Students[];
});
});
Students returns users._id in array with object inside, and I use that to find users object, and then I want to set null a field inside users object, that field named as "company". How I can do that? Thank you.
From what you posted (I took the liberty to use Promises but you can roughly achieve the same thing with callbacks), you can do something like:
User.find({'_id':{"$in" : Students}})
.then( users =>{
return Promise.all( users.map( user => {
user.company = null;
return user.save()
}) );
})
.then( () => {
console.log("yay");
})
.catch( e => {
console.log("failed");
});
Basically, what I'm doing here is making sure .all() user models returned by the .find() call are saved properly, by checking the Promised value returned for .save()ing each of them.
If one of these fails for some reasons, Promise.all() return a rejection you can catch afterhand.
However, in this case, each item will be mapped to a query to your database which is not good. A better strategy would be to use Model.update(), which will achieve the same, in, intrinsically, less database queries.
User.update({
'_id': {"$in": Students}
}, {
'company': <Whatever you want>
})
.then()
use .update but make sure you pass option {multi: true} something like:
User.update = function (query, {company: null}, {multi: true}, function(err, result ) { ... });

Mongoose query where with missing (or undefined) fields

I have an issue that I have a messy MongoDB database with a revised Mongoose scheme.
I want to be able to query using the where command, but if the field is missing or undefined in any found record then Mongoose returns an error.
For instance:
return this.find({personID: req.user._id})
.where('rangeBefore').lt(time);
This returns an error because some records do not have rangeBefore.
What I want to achieve is that any record without the rangeBefore field is filtered out (i.e. it fails the where test).
I have tried prefixing with exists like this:
return this.find({personID: req.user._id})
.exists('rangeBefore').where('rangeBefore').lt(time);
but I still get an error.
Can anyone suggest a way to ignore records with undefined fields, rather than returning an error?
If you just want to modify your existing query:
return this.find({ personID: req.user._id,
rangeBefore: { $exists: true, $ne: null } //also check for nulls
})
.where('rangeBefore').lt(time);
Or you can use the callback approach too if it fits:
this.find({personID: req.user._id,
rangeBefore: { $exists: true, $ne: null, $lt: time }
})
.exec(function(err, record) { });
You can do it like this, which returns a promise:
find({rangeBefore: { $exists: 1, $lt: time } }).exec()
Or use a callback:
find({rangeBefore: { $exists: 1, $lt: time } }).exec(function(err, record){
})
Your error message of:
Cast to number failed for value "undefined" at path "rangeBefore"
means that your time variable is undefined. A query like this will naturally ignore docs where rangeBefore doesn't exist.
So the problem is with your time variable, not your docs or query.

Resources