Sequelize.js - Invalid date problem in where clause [duplicate] - mysql

I am using Sequelize as my backend ORM. Now I wish to do some WHERE operations on a Date.
More specifically, I want to get all data where a date is between now and 7 days ago.
The problem is that the documentation does not specify which operations you can do on Datatypes.DATE
Can anyone point me in the right direction?

Just like Molda says, you can use $gt, $lt, $gte or $lte with a date:
model.findAll({
where: {
start_datetime: {
$gte: moment().subtract(7, 'days').toDate()
}
}
})
If you're using v5 of Sequelize, you've to include Op because the key was moved into Symbol
const { Op } = require('sequelize')
model.findAll({
where: {
start_datetime: {
[Op.gte]: moment().subtract(7, 'days').toDate()
}
}
})
See more sequelize documentation here

I had to import the Operators symbols from sequelize and use like so.
const { Op } = require('sequelize')
model.findAll({
where: {
start_datetime: {
[Op.gte]: moment().subtract(7, 'days').toDate()
}
}
})
According to the docs, for security reasons this is considered best practise.
See http://docs.sequelizejs.com/manual/tutorial/querying.html for more info.
Using Sequelize without any aliases improves security. Some frameworks
automatically parse user input into js objects and if you fail to
sanitize your input it might be possible to inject an Object with
string operators to Sequelize.
(...)
For better security it is highly advised to use Sequelize.Op and not
depend on any string alias at all. You can limit alias your
application will need by setting operatorsAliases option, remember to
sanitize user input especially when you are directly passing them to
Sequelize methods.

You can also use Sequelize.literal() to perform dates manipulation in SQL.
The following code works with Postgres, but I'm quite sure something similar could be done in other systems as well:
model.findAll({
where: {
start_datetime: {
$gte: Sequelize.literal('NOW() - INTERVAL \'7d\''),
}
}
})

This solution is without the moment.js library.
Between 7 days ago and now
const sevenDaysAgo = new Date(new Date().setDate(new Date().getDate() - 7));
models.instagram.findAll({
where: {
my_date: {
$gt: sevenDaysAgo,
$lt: new Date(),
},
},
});
Between now and 7 days from now
const sevenDaysFromNow = new Date(new Date().setDate(new Date().getDate() + 7));
models.instagram.findAll({
where: {
my_date: {
$gt: new Date(),
$lt: sevenDaysFromNow,
},
},
});
Notes:
$gt stands for "greater than". You could use $gte instead of $gt. $gte stands for "greater than or equal to". Same for $lte of course.
Technically speaking, you need both $lt and $gt to make sure that the date isn't into the future (per the original question).
Other answers show the use of [Sequelize.Op.gt] instead of $gt. Use that if on Sequelize v5.

Based on the other answers and comments, a way without using third party packages would be:
const sevenDaysFromNowResults = await db.ModelName.findAll({
where: {
createdAt: {
[Sequelize.Op.gte]: new Date(new Date() - (7 * 24 * 60 * 60 * 1000)) // seven days ago
}
}
})
The seven days are calculated using Date utility in milliseconds (days * 24hrs * 60mins * 60secs * 1000ms)

Related

How to compare case sensitive string data in Sequelize ORM for express.js?

I want to compare some case sensitive string data using sequelize. my string is "HARSH" and in db, it is "harsh" which should not be equal. I'm using where condition to find the data "HARSH" but in the response, I'm getting string data "harsh".
pReadings.user_model.findAll({
where: {
firstname: "HARSH"
}
})
The collation on the column needs to be ..._bin. It is probably ..._ci, meaning "case insensitive". It was either set that way by default or explicitly.
Please provide SHOW CREATE TABLE for assistance in changing it.
// search case insensitive nodejs usnig sequelize
const sequelize = require('sequelize');
let search = "testData"; // what ever you right here
pReadings.user_model.findAll({
where: {
firstname: sequelize.where(sequelize.fn('LOWER', sequelize.col('firstname')), 'LIKE', '%' + search.toLowerCase() + '%')
}
})
Try using the following,
pReadings.user_model.findAll({
where: sequelize.where(sequelize.fn('BINARY', sequelize.col('firstname')), 'HARSH')
// SELECT * FROM your_table WHERE BINARY(firstname) = 'HARSH';
})
For more information, check out Querying - Sequelize, under heading "Where > Basics". Good luck!
Your query is right. There is no problem with your query.
You could also try:
pReadings.user_model.findAll({
where: {
firstname: { $eq: 'HARSH' }
}
})

Sequelize creating SQL for DATE type

I`m using sequelize with mysql and I want to know if there is a way to use sequelize to create SQLs like these:
SELECT * FROM table WHERE DAY(dateAttribute) = 'chosen_day'
SELECT * FROM table WHERE MONTH(dateAttribute) = 'chosen_month'
I`ve tried to do something like this:
this.test= function () {
let searchingDate = "2017-05%";
return model.table.findAll({
where: {
dateAttribute: searchingDate
}
})
}
This works but it gives a deprecation warning saying that it will be remove in future versions.
Thanks for any help!
Found the solution!
So I used the sequelize.fn() with the Op.and function from sequelize. So the solution was:
this.test = function () {
return model.tableName.findAll({
attributes: ['myAttribute'],
where: {
dateAttribute: {
[sequelize.Op.and]: [
sequelize.where(sequelize.fn('MONTH', sequelize.col('dateAttribute')), 5),
sequelize.where(sequelize.fn('DAY', sequelize.col('dateAttribute')), 5),
]
},
otherAttribute: 'someValue'
}
})
}
This code generated this SQL query:
SELECT myAttribute FROM tableName WHERE (MONTH('dateAttribute') = 5 AND DAY('dateAttribute') = 5) AND otherAttribute = 'someValue'
I hope to save you guys from doing this long researching that I made!
Remember be HAPPY!

Sequelize Query Group by day objects found by parent property

So, I'm using sequelize with a mysql instance and I have this hierarchy : a task has n images and also n metadata key value pairs.
I want to get all images based on userId column of task, and afterwards get them grouped by 'createdAt' column taking into consideration the day, since a normal groupby will be pointless ( no objects share the same datetime ). I did lots of test to try to group, and I ended up using this query, which gives bad results ( I have like 11 images for a task, and it retrieves 4 ). Honestly, i don't know what I'm doing wrong. Any of you have any idea?
This is the code snippet:
var userId = security.utils.getKeycloakSubject(req);
var where = {
userId: userId
};
db.image.findAll({
include: [{
model: db.task,
include: [{
model: db.metadata,
as: 'metadata'
}],
where: where
}],
group: [db.Sequelize.fn('DAY', db.Sequelize.col('image.createdAt'))]
}).then(function (images) {
return res.json(images);
}, function (error) {
return res.status(500).json(error);
})
I saw your question and also found this: Sequelize grouping by date, disregarding hours/minutes/seconds
It is a question about group the DAY(createdAt), looks similar with yours.
And my solution of GROUP BY DAY() is look like:
item.findAll({
attributes:
[[sequelize.fn('DATE_FORMAT', sequelize.col('TimeStamp'), '%H'), 'dates']],
group: [sequelize.fn('DAY', sequelize.col('TimeStamp'))]
}).
then(function(result){console.log(result)
}).
catch(function(error){}).catch(function(error) {
console.log(error);
});
So the raw SQL likes: SELECT DATE_FORMAT('TimeStamp', '%H') as 'dates' FROM tableName GROUP BY DAY('TimeStamp');
Hope it helps you, or you can show us the SQL you want to use, maybe it is easier to help you too.
Good luck.

How to compare database fields in FeathersJS

I need to find all records where columnA <= columnB. I don't see any mention of this feature in the documentation.
Is it possible? How?
Since you are using Sequelize, as mentioned in this answer you should be able to accomplish this using sequelize.col. This condition can be added as a before find hook like this:
app.service('users').before({
find(hook) {
const { query } = hook.params;
query.columnA = { $gte: sequelize.col('columnB') };
}
});

Specifying specific fields with Sequelize (NodeJS) instead of *

Alright so I have a project in NodeJS where I'm utilizing Sequelize for a MySQL ORM. The thing works fantastically however I'm trying to figure out if there is a way to specify what fields are being returned on a query basis or if there's even a way just to do a .query() somewhere.
For example in our user database there can be ridiculous amounts of records and columns. In this case I need to return three columns only so it would be faster to get just those columns. However, Sequelize just queries the table for everything "*" to fulfill the full object model as much as possible. This is the functionality I'd like to bypass in this particular area of the application.
You have to specify the attributes as a property in the object that you pass to findAll():
Project.findAll({attributes: ['name', 'age']}).on('success', function (projects) {
console.log(projects);
});
How I found this:
The query is first called here: https://github.com/sdepold/sequelize/blob/master/lib/model-definition.js#L131
Then gets constructed here: https://github.com/sdepold/sequelize/blob/master/lib/connectors/mysql/query-generator.js#L56-59
Try this in new version
template.findAll({
where: {
user_id: req.params.user_id
},
attributes: ['id', 'template_name'],
}).then(function (list) {
res.status(200).json(list);
})
Use the arrays in the attribute key. You can do nested arrays for aliases.
Project.findAll({
attributes: ['id', ['name', 'project_name']],
where: {id: req.params.id}
})
.then(function(projects) {
res.json(projects);
})
Will yield:
SELECT id, name AS project_name FROM projects WHERE id = ...;
All Answers are correct but we can also use include and exclude as well
Model.findAll({
attributes: { include: ['id'] }
});
Model.findAll({
attributes: { exclude: ['createdAt'] }
});
Source