Sequelize time comparison failed after database replacement to postgreSQL - javascript

I've replaced MySQL database instead PostgreSQL and now I have issue when I'm trying find user through :
.find({ where: { resetPasswordToken: req.params.token, resetPasswordExpires: { gt: Date.now() } } })
.then(function(user){
if (!user) {
req.flash('errors', { msg: 'Password reset token is invalid or has expired.' });
return res.redirect('/forgot');
}
res.render('account/reset', {
title: 'Password Reset'
});
})
.catch(function(err){
return next(err);
});
This code was working before now I've message:
SequelizeDatabaseError: operator does not exist: timestamp with time zone > bigint
Date inside database is stored like: 2015-03-05 08:09:40.152+01
I will be very grateful because I don't know if my issue is caused by database migration or some type in my code. Thanks a lot!

Change your Date.now() to new Date(), looks like before you were storing time as integer.
{ gt: new Date() }

Related

Invalid prisma.user.findUnique() invocation

I can't seem to find what the error in the invocation is
function findUser(req, res) {
const username = req.body.username;
prisma.user.findUnique({
where: { username: username },
select: { username: true }
})
.then(data => {
res.send({
'userExists': data ? true : false
})
})
.catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while retrieving user."
})
})
.finally(async () => { await prisma.$disconnect()});
// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int #default(autoincrement()) #id
username String #unique
password String
salt String
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
}
From Prisma side everything is OK. The problem is probably req.body.username, if it's undefined you receive Invalid 'prisma.user.findUnique()' invocation.
You have to add validation for username, i.e.
if {typeof username !== string} return res.status(404).send('invalid username')
It might be the late response. I was also running into the same problem. But documentation saved my day. https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#findunique
You just have to add #unique attribute to your username field in schema.prisma, like below —
username String #unique #db.VarChar(255)
After looking at your code it seems that the username is missing from your req.body. I would suggest always verify the params you want to extract from req.body. I refactor your code to es6.
Here is the updated code you can try,
function findUser(req, res) {
// Destructure username from req.body
const { username } = req.body;
if(username == null) throw new Error('Username undefined');
// when property and value is same, you can write 'username' like below
prisma.user.findUnique({
where: { username },
select: { username: true }
})
.then(data => {
res.send({
'userExists': data ? true : false
})
})
.catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while retrieving user."
})
})
.finally(async () => { await prisma.$disconnect()});

How can I validate this in more elegant way?

Im trying to do login/register module in my project. This is my login function. I would like to have one function that will validate all things for me so I dont have to use so many "if" statements. I was trying to do with pure function but completely don't know how to do it. Can someone help me ?
const loginUser = async (req, res, next) => {
const { password, email } = req.body;
if (!email) {
return res.status(400).json({
message: "Error: Email cannot be blank.",
});
}
if (!password) {
return res.status(400).json({
message: "Error: Password cannot be blank.",
});
}
try {
const user = await User.findOne({ email: email });
if (!user)
return res.status(400).json({
message: "Invalid user",
});
if (!validPassword(password, user.password))
return res.status(400).json({
message: "Invalid password",
});
const { name, likedArr, _id } = user;
const token = crypto.randomBytes(32).toString("hex");
const userSession = new UserSession({ userId: _id, token });
await userSession.save();
return res.status(200).json({
message: "Valid login",
token: token,
user: {
name,
likedArr,
userId: _id,
},
});
} catch (err) {
next(err);
}
};
Abstracting my comments into an answer.
On Pure Functions:
If I understand pure functions correctly, I don't think you can have a pure function that calls an external API which may fail, since the same inputs may possibly return different results depending on the external state of the API (unless that API is guaranteed pure itself somehow). (Definition of a pure function)
On Repetition:
I genuinely think you don't have a lot of repetition here. Your code is clear and only has 4 conditionals, all for things you need to test for. You could abstract the similarities of your JSON returns into something like a template string depending on the conditions, but I think that could add clutter and opacity to your code, which isn't a good trade-off if you do it too much.
If you want an example of what I mean here:
if (!email) {
return res.status(400).json({
message: "Error: Email cannot be blank.",
});
}
if (!password) {
return res.status(400).json({
message: "Error: Password cannot be blank.",
});
}
Can become...
if (!email || !password) {
return res.status(400).json({
message: `Error: ${!email ? 'Email' : 'Password'} cannot be blank.`,
});
}

How to populate if field is not empty string if empty no need to populate?

I have an app that has huge amount of data previously saved in mongoDB. Now I need to populate some information if referencePeople not empty string. In my app referencePeople is string type instead of mongoose ObjectId type.
I don't want to change my schema. Is there any way to check referencePeople is empty or not before populate. or if empty avoid to populate.
schema:
var OrderSchema = new mongoose.Schema({
customer: {type: mongoose.Schema.Types.ObjectId,ref: 'Customer'},
referencePeople: String, // can be "" or "customer id"
......
});
Tried bellow code but got an exception Cast to ObjectId failed for value "" at path "_id"
exports.getOrders = function(req, res) {
Order.find({})
.populate('customer')
.populate({path: 'referencePeople', model: 'customer'})
.exec(function(error, orders) {
if(error) {
return res.status(400).send({msg: 'Error occurred while getting orders.', error: error});
}
return res.status(200).send(orders);
});
};
Now I want to populate referencePeople if it is not empty string.
Can I check before populate referencePeople is empty or not?
Yes, you need to use match clause of population query
So, your code should be smth like this:
exports.getOrders = function(req, res) {
Order.find({})
.populate('customer')
.populate({
'path': 'referencePeople',
'match': { 'referencePeople': {'$ne': ''} }
})
.exec(function(error, orders) {
if(error) {
return res.status(400).send({msg: 'Error occurred while getting orders.', error: error});
}
return res.status(200).send(orders);
});
};
Mongoose can’t handle multi-level population yet, and populated fields are not Documents. Nesting schemas is helpful but it’s an
incomplete solution. Design your schemas accordingly.
You are trying to reference the 'referencePeople' object using the existing ObjectID in the 2nd populate call
Try this
exports.getOrders = function(req, res) {
Order.find({})
.populate('customer')
.exec(function(error, orders) {
if(error) {
return res.status(400).send({msg: 'Error occurred while getting orders.', error: error});
}
//Try changing the referencePeople here
return res.status(200).send(orders);
});
};
REFERENCE: MongoDB

Mongoose won't validate user

this is my user model and this is my js file that searches for email in database.
When passing the correct email to following code, it doesn't find the user in database although the email is correct. Should I do it somehow different?
workflow.on('patchUser', function(token, hash) {
var conditions = { email: req.body.email.toLowerCase() };
var fieldsToSet = {
resetPasswordToken: hash,
resetPasswordExpires: Date.now() + 10000000
};
req.app.db.models.User.findOneAndUpdate(conditions, fieldsToSet, function(err, user) {
if (err) {
return workflow.emit('exception', err);
}
if (!user) {
workflow.outcome.errors.push("Can't find any email match it");
return workflow.emit('response');
}
workflow.emit('sendEmail', token, user);
});
});
user is always null even thought the correct email is passed.

mongoose save fails without error

As the title suggests I'm having problems with mongoose save method, which fails but does not produce an error.
I actually know why it fails, which is down to the userId field being marked as required but not being provided... but I don't know why it doesn't throw an error. I've exhausted google and stackoverflow looking at similar suggestions with no luck, so throwing it open to anyone who can help me!
Here's the code...
Model.js
var mongoose = require('mongoose');
var TimeSchema = new mongoose.Schema({
client: String,
matter: String,
activity: String,
tags: String,
description: String,
comments: [String],
startTime: Date,
startTimeUTC: Number,
endTime: Date,
endTimeUTC: Number,
duration: Number,
durationRnd: Number,
durationUnits: Number,
billable: Boolean,
rate: Number,
total: Number,
user: String,
userId: { type: mongoose.Schema.ObjectId, required: true }
}, {safe: true});
mongoose.model("Time", TimeSchema);
Controller.js
exports.addTime = function (req, res) {
console.log('Adding time: ' + JSON.stringify(req.body));
var time = new Time(req.body);
time.save(function (err) {
if (err) { res.send({'error' : err}); }
res.send(time);
});
}
EDIT - To clarify the callback is being called, take the following code for example.
exports.addTime = function (req, res) {
console.log('Adding time: ' + JSON.stringify(req.body));
var time = new Time(req.body);
console.log("time = " + time);
// TODO user
time.save(function (err) {
if (err) { handleError(res, err); }
console.log("ok");
Time.findById(time._id, function (err, found) {
console.log("found = " + found);
});
res.send(time);
});
}
and here's the console output
Adding time: {"description":"test","client":"","matter":"","activity":"","rate":
"","startTime":"2013-11-30T19:58:43.000Z","startTimeUTC":"1385841523000","endTim
e":"2013-11-30T19:58:45.000Z","endTimeUTC":"1385841525000","startLocale":"19:58"
,"startTimeLocale":"19:58:43","endLocale":"19:58","endTimeLocale":"19:58:45"}
time = { description: 'test',
client: '',
matter: '',
activity: '',
rate: null,
startTime: Sat Nov 30 2013 19:58:43 GMT+0000 (GMT Standard Time),
startTimeUTC: 1385841523000,
endTime: Sat Nov 30 2013 19:58:45 GMT+0000 (GMT Standard Time),
endTimeUTC: 1385841525000,
startTimeLocale: '19:58:43',
endTimeLocale: '19:58:45',
_id: 529a43750a366b6419000001,
comments: [] }
ok
POST /api/times 200 14ms - 313b
found = null
It is very possible to run into this error by naively not connecting to the database. Has happened several times to me. Make sure your mongoose.connect() is in place.
Problem solved, thanks to robertkelp.
Here's my revised code in case if ever helps anyone, but it appears the error was being thrown I just wasn't handling it correctly.
exports.addTime = function (req, res) {
console.log('Adding time: ' + JSON.stringify(req.body));
var time = new Time(req.body);
time.save(function (err) {
if (err) {
handleError(res, err);
}
else {
res.send(time);
}
});
}
My Problem was not solved by using findOne, it was solved by defining the fields i updated , in the model schema. so my code was like that:
User.findOne({email:data.userData.email}, function (err, user) {
if (!err && user!=undefined){
console.log(user);
var userDiscounts = user.discounts;
for(var i=0;i<userDiscounts.length;i++){
if (userDiscounts[i]!=undefined && userDiscounts[i].code=="XXXXXX"){
userDiscounts[i].claimed = true;
console.log('discount claimed');
}
}
user.discounts = userDiscounts;
user.fbDiscountClaimed = true;
user.save(function(err) {
if (err) console.log(err);
console.log('Saved Hashve-FB as claimed');
});
}
});
}
}
But the schema of the discount and user model was missing the definition of types of user.discounts so i added the following:
var UserSchema = new Schema({
name: String,
email: { type: String, lowercase: true },
role: {
type: String,
default: 'user'
},
hashedPassword: String,
provider: String,
salt: String,
messages:[],
discounts:[{
"name": String,
"description": String,
"created_at": String,
"updated_at": String,
"code": String,
"claimed": Boolean
}
],
facebook: {},
fbDiscountClaimed:false,
twitter: {},
google: {},
github: {}
});
UserSchema.pre('save',function(next){
var currentDate=new Date();
this.updatedAt=currentDate;
if(!this.createdAt){
this.createdAt=currentDate;
};
next();
});
When I use the .pre('save',fn) to create time, I forgot the next(), causing the data store to fail without error,I hope can help somebody!
For anyone can face a similar issue, I found that when populating a mongoose schema object from a json object that actually owns its “_id” property (even set to “null”), insert fails with no error.
Example:
var json = JSON.parse(req.body.time);
var time = new Time(json);
assuming that json._id is defined, no matter it's declared as a new "Time", when you try to insert with:
time.save(function (error) {
if (error) { res.send({'error' : error}); }
res.send(time);
});
error variabile is null but item was never inserted.
In this case I solved by deleting "_id" property before populating mongoose object so final code as follows:
var json = JSON.parse(req.body.time);
delete json._id;
var time = new Time(json);
time.save(function (error) {
if (error) { res.send({'error' : error}); }
res.send(time);
});
Regards
Angelo
Not directly related to the scenario described in the post, but I was getting the same error.
The issue was that I was not calling next(); at the end of the pre('save') function on the model definition.
For example:
cartSchema.pre('save', function(next) {
const currentDate = new Date();
this.modified = currentDate;
if (this.isNew) {
this.created = currentDate;
this.cartid = uuidv4();
}
next(); // this was missing :'(
});
I had a situation where the save callback was getting called, but the document wasn't changing. I haven't yet tracked down the root cause (some sort of validation thing probably) but the problem had something to do with one of the changes I made. So I just tried the changes one by one until I found the culprit.
(Feel free to edit this answer if you figure out more of this phenomenon)

Categories