MongoDB find document by date range - JavaScript - javascript

I want to find a specific document via a date range (beginDate should be greater or equals - and closeDate should be lesser or equals the current date).
The document looks like this:
{ "beginDate" : ISODate("2014-11-03T23:00:00Z"),
"closeDate" : ISODate("2014-11-10T23:00:00Z"),
"desc" : "Test",
"status" : "ok",
"playerId" : "ZLkQzaY7DDvwL8sRj",
"_id" : "kozi9eHcLYa2LbWDG" }
My query looks like this:
var doc = TestData.findOne({
playerId: player._id,
beginDate: { $gte: new Date(new Date().toISOString()) },
closeDate: { $lte: new Date(new Date().toISOString()) }
});
Unfortunately, this does not work. How can I solve it?
Any help would be greatly appreciated.

You've got the logic backwards on the comparisons so you need to swap the $lte and $gte usage. You want to find the docs where beginDate has a value less than or equal to the current time, and a closeDate has a value greater than or equal to the current time. You can also just use new Date() to get the current time.
var doc = TestData.findOne({
playerId: player._id,
beginDate: { $lte: new Date() },
closeDate: { $gte: new Date() }
});

Related

There is no calibration between MongoDB UTC time and local time

Data is stored and inquired through the API on the web page, and the API is using MongoDB.
The server space has been unified to UTC time so that the same results can be achieved in different time zones.
MongoDB uses the Mongoose schema as follows:
const userSchema = new Schema({
userId : {
type : String
},
score : {
type : Number
},
createdAt : {
type : Date,
default : Date.now
}
});
Because Date.now in the schema is in the createdAt field by default, it does not pass the Date value separately when querying the create or update of mongoose.
Considering the case where offset exists based on UTC time, the time is calculated using moment.js as follows:
// -540 offset value for KST 9 hours faster than UTC
const utc= moment.utc().add(offset, 'm').format('YYYY-MM-DDTHH:mm:ssZ');
let beginDate = new Date(utc);
let endDate = null;
let year = beginDate.getFullYear();
let month = beginDate.getMonth();
let date = beginDate.getDate();
// To view the full duration of the day
beginDate = new Date(new Date(year, month, date).setHours(0, 0, 0, 0));
endDate = new Date(new Date(year, month, date).setHours(23, 59, 59, 59));
// Find document
const user = await userSchema.aggregate([
{
$unwind : 'lists'
},
{
$match : {
'lists.createdAt' : {
$gte : beginDate,
$lte : endDate
}
}
},
...
]);
For example, if you make a query in Korea, the data inquiry may differ from the time after midnight and to 9 a.m. the next day.
What is wrong with the above parallax correction logic? I don't exactly understand the current problem.
Why so difficult? Simply use
{
$match : {
'lists.createdAt' : {
$gte : moment().startOf('day').toDate(),
$ltr : moment().endOf('day').toDate()
}
}
}
moment().startOf('day').toDate() returns the begin of current day in your local time zone. I live in Switzerland, thus it returns ISODate("2023-01-17T23:00:00.000Z")
But you can specify also a time zone, e.g.
moment.tz('Asia/Seoul').startOf('day').toDate();
ISODate("2023-01-17T15:00:00.000Z")
The problem is moment.utc().add(...) really modifies the time value. But that is not what you need to do, you like to change only the way how the time is displayed in your local time zone.
For comparison and calculations, the displayed value does not matter. All methods are done in UTC time only.

Mongodb aggregation query by date difference

I am trying to make a cron job which syncs my documents. It should try to do it x amount of times but only after 2h have passed since the last try. On each document I have "lastSyncAt" field which I can use.
{
"_id" : ObjectId("628d8c4ddb65027a2cfd1019"),
"calculatedAt" : "",
"count" : 0,
"createdAt" : "2022-05-25 01:54:21",
"lastSyncAt" : "2022-05-25 03:54:21"
}
How should I approach this?
Should I get the lastSyncAt value in pipeline and calculate difference between currentDate? How do I get only the hours portion of that in my pipeline?
Should I convert lastSyncAt into unix and get currentDate in unix substract them and divide by 7200 to see if it is greater than 2?
Or should I take another approach?
I'm not even sure what approach to take. Not looking for code but an idea how to handle this.
Thx
Update:
Thanks to #derek-menénedez I managed to get it working as shown below:
[
// Stage 1
{
$addFields: {
lastSyncAt: {
$dateDiff: {
startDate: {$dateFromString: {
dateString: "$lastSyncAt",
timezone: "Europe/Zagreb"
}},
endDate: "$$NOW",
unit: "minute",
timezone: "Europe/Zagreb"
}
}
}
},
// Stage 2
{
$match: {
lastSyncAt: {
$gt: 120
}
}
}
]
You can use the aggregation framework to achieve the things that you want:
https://mongoplayground.net/p/1RzPCYbeHEP
You can try to remove the projection on the example to validate the number of hours.
$dateFromString operator helps you to create a date from a string
$dateDiff operator helps you to extract the diff of two dates

check current timestamp present between two timestamp

I have a sending two timestamp start timestamp and end timestamp I have to check if the current timestamp in between the start and end timestamp then I have to change the variable value to true otherwise false.
{
"start_time":"2020-04-23T06:49:55.510Z",
"end_time":"2020-04-23T20:49:55.510Z",
"form_type":"5e54b4e4d76bf807091043ae",
"book_id":"5e56469d42f0c5647625fd45",
}
i am sending the data in this from in mongodb
sudo code something like this
var check = false
currentTime = Date.now()
if(currentTime < Start_time && currentTime < end_time)
{
check = true
}
I am not able to make a query for this.
currentTime = new Date();
db.model.find({"start_time" : { $gte : new
ISODate(currentTime.toISOString()) },
"end_time" : { $lte : new
ISODate(currentTime.toISOString()) }
});
Can you please try this Mongo query and check whether it is working or not? Please change the code according to your need.
You can use moment.js for that.
moment().utc();
This returns the current timestamp.
Then You need to convert your timestamp into a moment object.
compare_time = moment.utc('2020-04-21T06:49:55.510Z', 'YYYY-MM-DD[T]HH:mm:ss[Z]');
After doing that compare that to the current time using "isAfter()". Here is a working example
var current = moment.utc();
var compare_time = moment.utc('2020-04-21T06:49:55.510Z', 'YYYY-MM-DD[T]HH:mm:ss[Z]');
current.isAfter(compare_time); // true
You need to compare Date objects like so
var obj={
"start_time":"2020-04-23T06:49:55.510Z",
"end_time":"2020-04-23T20:49:55.510Z",
"form_type":"5e54b4e4d76bf807091043ae",
"book_id":"5e56469d42f0c5647625fd45",
}
var check=Date.parse(obj.start_time)<Date.now() && Date.now()<Date.parse(obj.end_time)
A fairly simple comparison to do using .getTime() on the Date object.
const jsonObject = {
"start_time": "2020-04-23T06:49:55.510Z",
"end_time": "2020-04-23T20:49:55.510Z",
"form_type": "5e54b4e4d76bf807091043ae",
"book_id": "5e56469d42f0c5647625fd45",
}
const startTime = new Date(jsonObject.start_time).getTime();
const endTime = new Date(jsonObject.end_time).getTime();
const currentTime = new Date().getTime();
console.log(startTime, currentTime, endTime);
console.log(startTime <= currentTime && currentTime <= endTime);
You can use mongodb-aggregation.
Your query would be like:
currentTime = new Date()
db.model.aggregate([
{
$set: {
value: {
$cond: [{currentTime: {$gt: "$start_time", $lt: "$end_time"}}, true, false]
}
}
}
])

Scalable Express + Mongoose Sort and Limit Pagination

I'm trying to work out how I can paginate my data efficiently. If I have a url such as: example.com/items?page=5, how can I retrieve the correct records every single time (so that the same record doesn't show up on another page)? I thought to I'd have to first sort the DB records first, then use mongoose to do a range query such as the one below.
How does this fare when the amount of records scales rapidly? I'm worried that the sorting process will take far too long and bottleneck the process. Any advice?
Submission.find({
/* First Case: Hour */
created: { $lt: new Date(), $gt: new Date(year+','+month+','+day+','+hour+','+min+','+sec) } // Get results from start of current hour to current time.
/* Second Case: Day */
created: { $lt: new Date(), $gt: new Date(year+','+month+','+day) } // Get results from start of current day to current time.
/* Third Case: Month */
created: { $lt: new Date(), $gt: new Date(year+','+month) } // Get results from start of current month to current time.
/* Fourth Case: Year */
created: { $lt: new Date(), $gt: new Date(year) } // Get results from start of current year to current time.
})
You can work on following query:
var query = Model.find(conditions).sort(sort).skip(skip).limit(limit);
where
condition will be say { age: { $gt: 20 } }
sort will be say { name: 1}
skip will be say 20
limit will be say 10
then execute the following query to get the records
return query
.exec()
.then(function (cursor) { ...... });

Searching Dates and Ignoring time and date in mongoDB node.js

I am using node.js and monodb database where I want to query records based on date and I want to ignore time and date only month and year will be matched here is my code:-
collection.find({ date: { "$gte": sDate, "$lt": eDate) } }).count(function (e, c) {
});
this is working but matching date and time as well how I can match only month and year? Please help me to solve this problem.
Edit:- some data from collection:-
{
"_id" : ObjectId("5535e76f82a964d011e34fcf"),
"VisitorId" : "5535e72a82a964d011e34fcb",
"date" : ISODate("2015-01-21T06:00:15.761Z"),
}
{
"_id" : ObjectId("5535e75f82a964d011e34fcf"),
"VisitorId" : "5535e72a82a964d011e34fcb",
"date" : ISODate("2015-04-21T06:00:15.761Z"),
}
I will pass two params i.e {month:"1",year:"2015"};
and in output first docs should be display.
Thanks
You could use the $where operator in your query:
collection.find({
"$where": function() {
return this.date.getMonth() == 0 && this.date.getFullYear() == 2015
}
}).count(function (err, data) {
// Handle err
});
However, query performance is rather compromised because using $where alone requires a table scan, it takes a global lock. You should use $where only when you can't express your query using another operator. If you must use $where , try to include at least one other standard query operator to filter the result set.
Other options are to modify your schema and store the month in its own property (if it's a common field in your queries). You are guaranteed better query performance since the field can be indexed.
The other option will be when query a specific month and year, create a query object that only looks for the start and the end of that specific month.
var sDate = new Date(2015, 0, 1);
var eDate = new Date(2015, 1, 1);
collection.find({ date: { "$gte": sDate, "$lt": eDate) } }).count(function (e, c) {
});

Categories