Node Js sequelize select query by month - node.js

Am new in Node Js, In my Node Js project am using sequelize ORM with MySql database.
This is my query i want to write select query by month.
This is my query SELECT * FROM cubbersclosure WHERE MONTH(fromDate) = '04'
Here fromDate field type is date
This my code:
var fromDate = '2019-04-01'
var fromDateMonth = new Date(fromDate);
var fromMonth = (fromDateMonth.getMonth()+ 1) < 10 ? '0' + (fromDateMonth.getMonth()+1) : (fromDateMonth.getMonth()+1);
CubbersClosure.findAll({
where:{
// select query with Month (04)... //fromMonth
}
}).then(closureData=>{
res.send(closureData);
}).catch(error=>{
res.status(403).send({status: 'error', resCode:200, msg:'Internal Server Error...!', data:error});
});
Here fromMonth get only month from date, so i want to write code select query by month.

I'm not sure but what about try this?
where: {
sequelize.where(sequelize.fn("month", sequelize.col("fromDate")), fromMonth)
}

for those of you looking for postgres, this is a somewhat hacky way to make this work (make sure to unit test this):
const results = await models.users.findAll({
where: this.app.sequelize.fn('EXTRACT(MONTH from "createdAt") =', 3)
});
you can also take this a step further and query multiple attributes like so:
const results = await models.table.findAll({
where: {
[Op.and] : [
this.app.sequelize.fn('EXTRACT(MONTH from "createdAt") =', 3),
this.app.sequelize.fn('EXTRACT(day from "createdAt") =', 3),
]
}
});

Related

Mongoose, NodeJS & Express: Sorting by column given by api call

I'm currently writing a small API for a cooking app. I have a Recipe model and would like to implement sorting by columns based on the req Parameter given.
I'd like to sort by whatever is passed in the api call. the select parameter works perfectly fine, I can select the columns to be displayed but when I try to sort anything (let's say by rating) the return does sort but I'm not sure what it does sort by.
The code i'm using:
query = Recipe.find(JSON.parse(queryStr));
if(req.query.select){
const fields = req.query.select.split(',').join(' ');
query = query.select(fields);
}
if(req.query.sort){
const sortBy = req.query.sort.split(',').join(' ');
query = query.sort({ sortBy: 1 });
} else {
query = query.sort({ _id: -1 });
}
The result, when no sorting is set: https://pastebin.com/rPLv8n5s
vs. the result when I pass &sort=rating: https://pastebin.com/7eYwAvQf
also, when sorting my name the result is also mixed up.
You are not using the value of sortBy but the string "sortBy". You will need to create an object that has the rating as an object key.
You need the sorting object to look like this.
{
rating: 1
}
You can use something like this so it will be dynamic.
if(req.query.sort){
const sortByKey = req.query.sort.split(',').join(' ');
const sortByObj = {};
sortByObj[sortByKey] = 1; // <-- using sortBy as the key
query = query.sort(sortByObj);
} else {
query = query.sort({ _id: -1 });
}

TypeORM : Generate query with nested AND and OR

I am using NodeJS + TypeORM + PostgreSQL
I find it difficult to generate queries based on my requirements.
I need to generate the following query:
select * from clinics where status = 1 and (last_sync_date < x or last_sync_date is null)
Here x is current date - 10 days.
I tried the following query:
let now = Date();
now.setDate(now.getDate() - 10);
let clinics = await clinicRepo.find({
where: [
{ status: 1, last_sync_date: LessThan(now) },
{ last_sync_date: IsNull() }
]
});
But the result is this:
select * from clinics where (status = 1 and last_sync_date < x) or last_sync_date is null;
What do I need to change in the code above?
I want to use find so that I can load relations as well.
You can solve this by creating the query with js conditions and then assign it to the FindConditions.
For example:
const whereCondition = testResultId ?
{patientId, id: Not(testResultId), clinicId} :
{patientId, clinicId}
const tr = await TestResult.findOne({
where: whereCondition,
})
Or you can use Raw operator:
let clinics= await clinicRepo.find({
where : [
{status: 1,
last_sync_date: Raw(alias => `(${alias} < ${now} OR ${alias} IS NULL)`}
]
});

Sequelize raw query not properly printed

I am trying to write query in sequelize but query is not working below is my query that I write in sequelize
var homePosts = db.postbox.findAll({
where: {
user_id: {
$or: {
$eq: id,
$in: [id]
}
}
},
attributes: ["user_posts_id"],
limit: 5
});
return homePosts;
Node js print result query
Executing (default): SELECT `user_posts_id` FROM `user_posts_boxes` AS `user_posts_boxes` WHERE `user_posts_boxes`.`user_id` = '[object Object]' LIMIT 5;
[]
It prints object instead of variable value and print the actual query that sequelize prepare.
My actual raw query is following which I actually want to convert into sequelize
SELECT `user_posts_id` FROM `user_posts_boxes` AS `user_posts_boxes` WHERE ( `user_posts_boxes`.`user_id` = '5' OR `user_posts_boxes`.`user_id` IN (select following_id from friend WHERE friend.follower_id = user_posts_boxes.user_id and friend.status='A' and friend.following_id=5)) LIMIT 5
I had the same issue with Sequelize 5. Use Symbol based operator and it should be fine https://github.com/sequelize/sequelize/issues/8417

how to pass 2 dates to req params to find data between 2 dates

I am creating a rest API for my company for reporting
Routs to pass dates to find data from 2 given dates
router.get('/smDcr/:currentDate?&:lastDate:', authorize, getDcrBetweenDates);
Controller action to get the data between dates
exports.getDcrBetweenDates = async(req, res, next) => {
try{
const lastDate = req.params.lastDate;
const currentDate = req.params.currentDate;
console.log(lastDate);
const dcr = await Dcr.find({
where: {
createdAt: {
$between:[currentDate, lastDate]
}
}
});
if(!dcr) return res.status(400).json({message: "No DCR found between mentioned Dates!!"});
return res.status(200).json({ dcr});
}catch(ex){
next(ex)
}
}
while passing parameter in postman I am getting all reports not specific to the dates given in params
http://localhost:3000/smDcr/?currentDate=2019/09/11&?lastDate=2019/09/11
You don't need to use $where condition, you just can set your request object inside find function
I think you should use $gte and $lte operators, instead of $between (cf #ponzao answer)
Here is an example :
const dcr = await Dcr.find({
"createdAt": {
"$gte": new Date(currentDate),
"$lt": new Date(lastDate)
}
});
EDIT:
If it still doesn't works, it is probably because your dates are not formatted, maybe you should use a date library, like moment, and try like this :
const moment = require('moment');
const dcr = await Dcr.find({
"createdAt": {
"$gte": new Date(moment(currentDate, 'YYYY/MM/DD').format()),
"$lt": new Date(moment(lastDate, 'YYYY/MM/DD').format())
}
});
Hope it helps.
It will be better if you use query strings instead of query params for atleast dates. In the route you provided that is :
router.get('/smDcr/:currentDate?&:lastDate:', authorize, getDcrBetweenDates);
using ?&: in url to pass 2nd date value will get interpreted as querystring because of (?).
And you are accessing this end point by calling this :
http://localhost:3000/smDcr/?currentDate=2019/09/11&?lastDate=2019/09/11
In this, currentDate will be considered as query string and same is the case with lastDate
So I would suggest you to use this instead :
router.get('/smDcr', authorize, getDcrBetweenDates);
And in your controller, access the values like this :
const lastDate = req.query.lastDate;
const currentDate = req.query.currentDate;
And to access it you should be calling :
http://localhost:3000/smDcr?currentDate=2019/09/11&lastDate=2019/09/11
Here is a official doc for routing.
Express Routing

How do I query a tstzrange with Sequelize?

I have a range of timestamp with timezone stored in one column of my PostgreSQL database, e.g:
timeRange (tstzrange)
["2019-02-10 23:00:00+00","2019-03-09 23:00:00+00")
I want to query my database based on that column, testing if a given date range is contained by the range in my column.
According to the PostgreSQL docs, I can query a range contained by another range with the <# operator:
Operator | Description | Example | Result
<# | range is contained by | int4range(2,4) <# int4range(1,7) | t
According to the Sequelize docs, this can be done using the operator $contained:
$contained: [1, 2] // <# [1, 2) (PG range is contained by operator)
I have tried querying using this operator:
const start = '2019-02-11T00:30:00.000Z';
const end = '2019-02-08T02:30:00.000Z';
MyModel.findOne({
where: {
timeRange: {
$contained:
[
new Date(start),
new Date(end)
]
}
}
});
This doesn't work and gets the error
error: operator does not exist: tstzrange = timestamp with time zone
The query looks like this
'SELECT * FROM "model" AS "model" WHERE "model"."timeRange" = \'2019-06-26 22:00:00.000 +00:00\'::timestamptz;'
This probably explains why I got the PostgreSQL error. How can I properly format the query to get what I want?
Using this similar question, I figured out a workaround but I'm not sure why or how it works : Query with date range using Sequelize request with Postgres in Node
var Sequelize = require('sequelize');
const Op = Sequelize.Op;
const start = '2019-02-11T00:30:00.000Z';
const end = '2019-02-08T02:30:00.000Z';
MyModel.findOne({
where: {
timeRange: {
[Op.contained]:
[
new Date(start),
new Date(end)
]
}
}
});
If anyone has an explanation, I would be happy to hear it

Resources