Running sequelize with two where conditions - javascript

I have a mysql db instance with a table consisting of a various fields. Relevant fields are start, start time, and status
start: YYYY-MM-DD
startTime: HH:mm:ss
status: ENUM('cancelled', 'scheduled, etc)
If I want to get a list of all entries that don't have status = 'cancelled' and that occur today or after, I would write this:
return {
where: {
status: {
$ne: 'cancelled'
},
$or: {
start: { $gte: moment().utc().format('YYYY-MM-DD') },
$and: {
isRepeating: 1,
$or: [{
end: {
$gte: moment().format(),
}
},
{
end: {
$eq: null,
}
}]
},
}
},
I am trying to modify this query to not only give me entries that occur today or after, but also greater than right now (time wise, UTC). My attempt was to first filter based on startTime, and then filter based on startDate, but it does not seem to be working:
return {
where: {
status: {
$ne: 'cancelled'
},
$or: {
startTime: { $gt: moment.utc().format('HH:mm:ss') },
$and: {
start: { $gte: moment().utc().format('YYYY-MM-DD') },
$and: {
isRepeating: 1,
$or: [{
end: {
$gte: moment().format(),
}
},
{
end: {
$eq: null,
}
}]
}
},
}
},
(does not work, because it just returns everything!)
I also cannot do something more simple like
where: {
startTime: { $gt: moment.utc().format('HH:mm:ss') },
start: { $gte: moment().utc().format('YYYY-MM-DD') },
}
Because then it will ignore, for example, entries that occur tomorrow date wise, but occur earlier in the day than the current timestamp.
Thanks!

You can use Op.and operator to combine those conditions.
const { Op } = require("sequelize");
...
where: {
[Op.and]: [
startTime: { $gt: moment.utc().format('HH:mm:ss') },
start: { $gte: moment().utc().format('YYYY-MM-DD') }
]
}
...

Related

How to write an or statement in mongodb using the find function in mongoose

I'm trying to check if there is a booking in a range of time. Not sure how to use the or condition in mongodb using mongoose.
Here is what I have:
const appoinments = await Appointment.find({
seller: seller._id,
startTime: {
$gt: ISODate(new Date(req.body.startTime).toISOString),
$lt: ISODate(new Date(req.body.endTime).toISOString),
},// I WANT TO ADD THE OR TO THIS TWO QUERIES
endTime: {
$gt: ISODate(new Date(req.body.startTime).toISOString),
$lt: ISODate(new Date(req.body.endTime).toISOString),
},
});
I want to check and find for any appointment that conflict with new appointment that is about to be added or any appointment that ends during that time of the appointment.
Here is what my Appointment looks like:
const appointmentSchema = new mongoose.Schema({
seller: {
type: mongoose.Schema.Types.ObjectId,
ref: "Seller",
},
startTime: {
type: Date,
required: true,
},
endTime: {
type: Date,
},
});
You can simply use the or() member function that mongoose provides. It works just like the $or operator defined in the mongoose documentation.
I hope it helped!
const appoinments = await Appointment.find().or([
{
startTime: {
$gt: ISODate(new Date(req.body.startTime).toISOString),
$lt: ISODate(new Date(req.body.endTime).toISOString),
}
},
{
endTime: {
$gt: ISODate(new Date(req.body.startTime).toISOString),
$lt: ISODate(new Date(req.body.endTime).toISOString),
},
}
]);

Insanely slow Mongodb group query

I'm trying to aggregate $sum between 2 dates stored as UTC strings (yyyy-mm-dd-hh). It takes 5+ seconds to get the results. My collection has 5 million+ docs.
{
$match: {
start: {
$gte: '2020-08-01-00',
$lte: '2021-08-01-00'
}
}
},
{
$group: {
_id: {
symbol: '$symbol'
},
unverifiedCount: {
$sum: {
$cond: {
if: { $eq: ['$isVerified', false] }, then: '$count', else: 0
}
}
},
verifiedCount: {
$sum: {
$cond: {
if: { $eq: ['$isVerified', true]}, then: '$count', else: 0
}
}
}
}
}, {
$sort: {
unverifiedCount: -1
}
}
Tried using $toDateString but performance remained the same

Am I using Mongo's $and and $expr incorrectly?

Here is my query:
ctas.updateMany({
$and: [
{$expr: { $lt: ['$schedule.start', () => Date.now()] }},
{$expr: { $gt: ['$schedule.end', () => Date.now()] }}
]
},
{
$set: {isActive: true}
}).then(res => {
const { matchedCount, modifiedCount } = res;
console.log(`Successfully matched ${matchedCount} and modified ${modifiedCount} items.`)
}).catch(e => console.error(e));
I'm absolutely positive that start is less than Date.now() and end is greater than Date.now(), but I'm not getting any matches. Is my syntax wrong?
a snippet of my document in mongo:
schedule: {
start: 1642564718042,
end: 3285129434744
}
Edit: In case it makes a difference, I'm writing this code as a mongo scheduled trigger.
Update: If I replace the second expression with an obviously truth expression, { isActive: false }, it matches all the documents. Obviously Date.now()*2 (what I used to set schedule.end) is greater than Date.now(), so why is that second expression failing?
Missing $. And make sure your field paths are correct. $schedule.start and $schedule.end.
And another concern is that both schedule.start and schedule.end are with Timespan value. So you need to cast them to date via $toDate.
db.collection.update({
$and: [
{
$expr: {
$lt: [
{
$toDate: "$schedule.start"
},
new Date()
]
}
},
{
$expr: {
$gt: [
{
$toDate: "$schedule.end"
},
new Date()
]
}
}
]
},
{
$set: {
isActive: true
}
})
Sample Mongo Playground

Mongodb javascript variable

I need to use the string value in nodejs in a mongo query. But on passing those variable in [] I get back an undefined object. Putting the actual value however does give the right answer
var myquery = [
{
$match: {
time: {
$gte: [start_time],
$lt: [end_time]
},
payeeFsp : [dfsp_given]
}
},
{
$group: {
_id: null,
total: {$sum:"$amount"}
}
}
];
dbo.collection("transaction_history").aggregate(myquery).toArray(function(err, res) {
if (err) throw err;
console.log(res);
db.close();
});
Why would you put the variables in array?
I think the query should be like this
var myquery = [
{
$match: {
time: {
$gte: start_time,
$lt: end_time
},
payeeFsp : dfsp_given
}
},
{
$group: {
_id: null,
total: {$sum:"$amount"}
}
}
];

Mongodb : Find and insert if time slots doesn't conflict with other time slots

I have an event schema :
owner: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
participants: [
{
type: Schema.Types.ObjectId,
ref: 'User'
}
],
createdOn: { type: Date, default: Date.now },
lastModified: { type: Date, default: Date.now },
active:{ type: Boolean, default: false },
eventDate: { type: Date },
startAt: { type: Date },
endAt : { type: Date },
timeZone:{ type: 'String', required: true }
I want to insert events such that the events dont overlap other events (for eg: if an event is on 2018-2-14 starting at 3:00 am and ending at 4:00 am, there should be no event on this date between 3:00 am and 4:00 am, other than this event. But there can be a event on this date for other time slots but not between 3:00 am to 4:00 am)
I tried the following logic but I didn't seem to work. Whats wrong with this logic:
const eventData = {
owner: req
.body
.owner
.trim(),
startAt: setTimeToDate(req.body.eventDate, req.body.startAt.trim(), req.body.timeZone),
endAt: setTimeToDate(req.body.eventDate, req.body.endAt.trim(), req.body.timeZone),
eventDate: moment(req.body.eventDate).toISOString(),
participants: req.body.participants,
active: true,
timeZone: req.body.timeZone
};
Events.find({
$and: [
{
"eventDate": new Date(eventData.eventDate)
}, {
$or: [
{
$and: [
{
"startAt": {
$lt: new Date(eventData.startAt)
}
}, {
"startAt": {
$lte: new Date(eventData.endAt)
}
}
]
}, {
$and: [
{
"endtAt": {
$gte: new Date(eventData.startAt)
}
}, {
"endtAt": {
$gt: new Date(eventData.endAt)
}
}
]
}
]
}
]
})
.exec(function (err, results) {
const count = results.length;
if (!count) {
const newEvent = new Events(eventData);
newEvent.save((err) => {
if (err) {
res
.status(400)
.json({success: false, message: 'Could not create this availability.'});
}
res
.status(200)
.send({success: true, message: 'Your availability on this date is created successfully.'});
});
}
});
So what I did was to find out the chances that an event can overlap with other events.
The first case is when the start time of the new event that I'm gonna insert is between start time and end time of any other events.
The second case is similar and the only difference is this time I check if the end time of the new event that I'm gonna insert is between the start time and end time of any other events.
The third case is when the start time of the new event is less than the start time of any other events and the end time of new event is greater than the end time of any other events.
The 3 above scenarios cover all the cases of time slot overlappping
The query for the same is as shown below
{
$or: [
{
$and: [
{
"startAt": {
$lte: new Date(new Date(eventData.startAt))
}
}, {
"endAt": {
$gte: new Date(new Date(eventData.startAt))
}
}
]
}, {
$and: [
{
"startAt": {
$lte: new Date(new Date(eventData.endAt))
}
}, {
"endAt": {
$gte: new Date(new Date(eventData.endAt))
}
}
]
}, {
$and: [
{
"startAt": {
$gte: new Date(new Date(eventData.startAt))
}
}, {
"endAt": {
$lte: new Date(new Date(eventData.endAt))
}
}
]
}
]
}
Okay I'm not sure but I see two flaws in the logic
Basically you need any records which has startAt or endAt between your new startAt and endAt
in the first condition, You want the slots who have startAt time between new startAt and endAt, So for that the logic would be
startAt greater than new startAt and less than equal to new endAt
$and: [
{
"startAt": {
$gt: new Date(eventData.startAt)
}
}, {
"startAt": {
$lte: new Date(eventData.endAt)
}
}
]
Also You want records which has endAt after new startAt and before new endAt, so for that logic would be
endAt greater than new startAt and less than equal to new endAt
$and: [
{
"endAt": {
$gt: new Date(eventData.startAt)
}
}, {
"endAt": {
$lte: new Date(eventData.endAt)
}
}
]
I think this would work.
EDIT Okay third condition would be, Slots that are starting before new StartAt and ending after new EndAt, Because they would not fall in above conditions
$and: [
{
"startAt": {
$lt: new Date(eventData.startAt)
}
}, {
"endAt": {
$gt: new Date(eventData.endAt)
}
}
]

Categories

Resources