MongoDB query based on date plus time - mongodb

i've to run a query like this (sql) in MongoDb 4:
SELECT * FROM log WHERE DATE_ADD(created_at, INTERVAL 2 HOUR) < NOW()
Basically, I want to find all the documents, in the PENDING state, whose creation date PLUS TWO HOURS is less than now .. Let me explain: I want to find all the documents in the PENDING state that have been in PENDING for more than two hours.
I feel stupid, but I am failing to do this with MongoDb.
I also created a playground:
https://mongoplayground.net/p/4bifqiX2KMJ
Can you help me?

You can add hours in ISO date using $add, convert string date to ISO date using dateFromString,
let date = new Date();
db.collection.find({
status: "pending",
$expr: {
$lt: [
{
$add: [
// convert string date to ISOdate, if its already then use only "$inserted_at"
{ $dateFromString: { dateString: "$inserted_at" } },
// add milliseconds
7200000 // (60*60*2000)
]
},
date
]
}
})
Playground
Or subtract from current date and then compare the condition,
let date = new Date();
date = new Date(date.getHours()-2); //subtract 2 hours
db.collection.find({
status: "pending",
$expr: {
$lt: [
{ $dateFromString: { dateString: "$inserted_at" } },
date
]
}
})
Playground

Related

Query to get data from mongodb using ObjectId ("xxxxxxxxx").GetTimestamp()

I am starting in the world of mongodb.
I have the following question:
I want to find the items that were posted from date x. In the records I have no date but I can get it from this statement:
ObjectId ("5ffdc390fdd1596ca5870bec"). GetTimestamp ()
whose result is: ISODate ("2021-01-12T15: 43: 12Z")
How could I create a query that returns all the records that were created from a given date, for example from 2021-01-12?
Thank you very much.!
The mongo Shell is an interactive JavaScript interface to MongoDB, so the solution by Leftium should work.
function objectIdWithTimestamp(timestamp) {
/* Convert string date to Date object (otherwise assume timestamp is a date) */
if (typeof(timestamp) == 'string') {
timestamp = new Date(timestamp);
}
/* Convert date object to hex seconds since Unix epoch */
var hexSeconds = Math.floor(timestamp/1000).toString(16);
/* Create an ObjectId with that hex timestamp */
var constructedObjectId = new ObjectId(hexSeconds + "0000000000000000");
return constructedObjectId
}
/* Find all documents created between Jan 12th, 2021 and Jan 13th, 2021 */
db.mycollection.find({ _id: { $gt: objectIdWithTimestamp('2021/01/12'), $lt: objectIdWithTimestamp('2021/01/13') } });
You can query it directly:
db.collection.find({
$expr: {
$gte: [ {$toDate: "$_id"}, ISODate("2021-01-01T00:00:00Z") ] }
}
)
Usually I prefer the moment.js library, could be this for example:
db.collection.find({
$expr: {
$gte: [ {$toDate: "$_id"}, moment().startOf('day').subtract(3, 'days').toDate() ] }
}
)

Mongodb group epoch to YYYY-MM-DD

So currently store start and end time that a user listens to our stations in epoch format, however now I need to do a query that groups listeners if they where listening with an hour block.
For example:
last 7 days Query would need to go back 7 days normally I would just do something like this
items.find({
history.$.starttime: {
$gte: ISODate("2020-07-10T00:00:00.000Z"),
$lt: ISODate("2020-009-17T24:59:59.000Z")
}})
However we don't store the date in this format we store it looking like this.
So how do a search between dates if the dates are in epoch format?
I have tried
{'history': {'$elemMatch':{'starttime': {'$gte':1592966066060}}}
UPDATE:
this works
{"history.starttime":{$gte:1593236606706}}
You can convert timestamp to ISO date using $toDate, like this,
db.collection.aggregate([
{
$addFields: {
startTimeDate: {
$toDate: "$startTime"
},
endTimeDate: {
$toDate: "$endTime"
}
}
},
{
$match: {
startTimeDate: {
$gte: ISODate("2020-01-20T21:20:00Z")
}
}
}
])
You can removed that added field using:
{
$project: {
startTimeDate: 0,
endTimeDate: 0
}
}
Working Playground: https://mongoplayground.net/p/XiEYVxvmfpv
Convert the times to Unix timestamps in your application, specify the timestamps in the query.

MongoDB group by date and fill zero counts

I would like to group my search results by date. The results are then also counted.
var fromDate = new Date(req.query.fromDate);
var toDate = new Date(req.query.toDate);
global.databaseStatistic.collection(global.ARTICLEPRESS).aggregate([
{
$match: {
article: { $in: articleIdArray },
date: { $gte: fromDate, $lte: toDate }
}
},
{
$group: {
"_id": {
"date": {
$dateToString: { format: "%d.%m.%Y", date: "$date" }
}
},
"count": { $sum: 1 }
}
}
])
This works perfectly, but I would also like to show all days that have a count of zero. It should be so displayed every day within an interval, also having a count of zero. How can I do that?
as it looks very trivial - it is not.
There is no way to have a reference sequence to compare with, even $lookup cannot help as this a kind of inner join type.
The way you could have this done is a kind of post process of result-set returned to mongoose.
The steps I have in mind could be:
create array of dates from req.query.fromDate to req.query.toDate formated in the same way as in query
remove entries in array which we have in result set
merge our array with count:0 and date
sort results (if needed)
any comments welcome!

Get data between two dates mongo

I need to query the data between two dates.
I was pushing data into mongo where dates are in the format : 13-10-2015 15:08:22
Is there a way to do it?
Can't i tell mongo to compare these as dates with format explicilty mentioned
You can use the generic $gte and $lte query modifiers when dealing with Dates in mongo
{ $gte: startDate, $lte: endDate }
should work just fine (where endDate and startDate are Javascript Date objects)
You can use aggregate function in mongodb.
You can get dates using this :
let todayDate = new Date();
let beforeDate = new Date();
beforeDate.setDate(beforeDate.getDate() - 15);
[Here 15 is days. It will subtract 15 days from current date].
TableName.aggregate([
{
"$match":
{
"Date":
{
"$lte": todayDate,
"$gte": beforeDate
}
}
}
])
let today = new Date();
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
{
$match: {
createdAt: {
$gte: sevenDaysAgo,
$lte: today,
},
},
},

Timezone in mongo query

I have data inserted in UTC time format in mongodb. I want timings to be converted based on the timezone. Is there any possibility to do so in mongo query?
In mongo version 3.6 timezone has been added, mongo doc
expression to extract date part with timezone is
{ date: <dateExpression>, timezone: <tzExpression> }
we can either specify the timezone or offset while getting the date parts.
see my answer posted here
to get date from date with timezone America/Chicago
{ $month: {
date: new Date(),
timezone: "America/Chicago"
} }
or with offset
{ $month: {
date: ISODate(),
timezone: "-0500"
} }
Let consider your document contains ISODate as below :
db.collection.insert({"date":new Date()})
Above query insert date in ISODate format now you want to convert this ISODate into give timeZone.
Suppose you want to convert above date to Eastern Daylight Saving Time ( EDT ) epoch time zone conertor then offset converted as 14400 * 1000. First convert ISODate to timeStamp and then use substract EDT OffsetintimeStampand then converttimeStamptoISODate` again.
Check below aggregation query :
db.collection.aggregate({
"$project": {
"timestamp": { //convert ISODate tom timestamp
"$subtract": [{
"$divide": [{
"$subtract": ["$date", new Date("1970-01-01")]
}, 1000]
}, {
"$mod": [{
"$divide": [{
"$subtract": ["$date", new Date("1970-01-01")]
}, 1000]
}, 1]
}]
}
}
}, {
"$project": {
"timeZoneTimeStamp": {
"$subtract": [{ //substract timestamp to given offset if offset will in postive then replace subtract to add
"$multiply": ["$timestamp", 1000]
}, 14400000]
}
}
}, {
"$project": {
"timeZoneTimeStamp": 1, //converted timeZoneTimeStamp if required
"_id": 0,
"newDate": { // newDate is converted timezone ISODate
"$add": [new Date(0), "$timeZoneTimeStamp"]
}
}
})
NOTE :
In above query conversion from ISODATE to timeStamp ref. here
In case if the dates are not changed and constant e.g. something like created_record_date then whichever timezone data you need it, you should pre-calculate and save (as String) along with the same document so that you don't have to run the huge processing at the runtime which could slow down the execution time. in case you have existing records and you want to store the various different timezone data along with the records, think about running a Map-Reduct job and update the documents separately. (let me know if you need the code for that). However, if this date field can be changed as per the business logic then its wise to calculate at runtime. both techniques have their different use cases and their pros and cons.
-$
If you are using mongoose (probably also works in native driver):
import moment from 'moment-timezone'; // this is needed to use .tz() method
import mongoMoment from 'mongodb-moment';
// Initalize mongodb-moment so you can use moment() object directly in mongo query
mongoMoment(moment);
// Add timezone to your_date
const date = moment(your_date)
.tz("Europe/Zagreb");
// Make $gte/$lte queries with date ...