Inconsistent Date field in mongodb , why happen , how to identify and fix - mongodb

I have identified recently date fields in my mongod 4.0 with such a content:
"last_update" : ISODate("-229-05-06T07:23:23Z")
"last_update" : ISODate("50170-12-13T06:03:34Z")
"last_update" : ISODate("0000-07-23T05:19:55Z")
So my question:
Is mongodb allowing such freedom for date fields ( signed 64bit integer of type date ) ?
According to this :
https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#conversion-table
It seems like the format is OK?
Datetime [year before 1970 or after 9999] {"$date": {"$numberLong": <64-bit signed integer giving millisecs relative to the epoch, as a string>}}
Attempts to insert it from mongo shell ISO date helper as expected did not allowed me:
MongoDB Enterprise mongos> db.test.insert({ "created" : ISODate("-229-05-06T07:23:23Z") })
2021-01-29T11:47:53.484+0100 E QUERY [js] Error: invalid ISO date: -229-05-06T07:23:23Z :
ISODate#src/mongo/shell/types.js:65:1
#(shell):1:31
MongoDB Enterprise mongos>
But at the same time insert affected fields from the original document in another collection was not having issues:
MongoDB Enterprise mongos> var x = db.theAffectedCollection.findOne({_id:ObjectId("5c6e8c6ce0ebbb309ce0dc06")},
{created:1,last_update:1})
MongoDB Enterprise mongos> use test
MongoDB Enterprise mongos> db.test.insert(x)
WriteResult({ "nInserted" : 1 })
MongoDB Enterprise mongos> db.test.find()
{ "_id" : ObjectId("5c6e8c6ce0ebbb309ce0dc06"), "created" : ISODate("-229-05-06T07:23:23Z"), "last_update" : ISODate("-229-05-06T07:23:23Z") }
mongoexport result:
"created":{"$date":"-0229-05-06T07:23:23.000Z"}
Luckily the document _id timestamp show the exact creation date:
ObjectId("5c6e8c6ce0ebbb309ce0dc06").getTimestamp()
ISODate("2019-02-21T11:33:00Z")
So I could easily fix it ...

Issue clarified , in the extended json format supported by mongoDB the date field in shell mode ( not strict mode ) can support dates outside the range 0000-9999 and it is understood by mongodb like signed 64bit integer in the form:
mongos> new Date(1313124124122341)
ISODate("43581-03-31T21:08:42.341Z")
mongos>
mongos> new Date(-121213232233222)
ISODate("-1872-11-27T01:42:46.778Z")
mongos>
In Strict mode, is an ISO-8601 date format with a mandatory time zone field following the template YYYY-MM-DDTHH:mm:ss.mmm<+/-Offset>.
In Shell mode, is the JSON representation of a 64-bit signed integer giving the number of milliseconds since epoch UTC.
Strict Mode:
{ "$date": "<date>" }
mongo Shell Mode:
new Date ( <date> )
https://docs.mongodb.com/manual/reference/mongodb-extended-json-v1/
Internally, Date objects are stored as a signed 64-bit integer representing the number of milliseconds since the Unix epoch (Jan 1, 1970).
Not all database operations and drivers support the full 64-bit range. You may safely work with dates with years within the inclusive range 0 through 9999.
So thanks alot #Alex & #Wernfried to provide the hints !

Related

i am not getting data till today date in mongodb using $gte

what i want is to get the users who have created there account in between the range of dates and also want to get the customer with order count greater then 1 for those new customers, so what i am doing is trying to get the data greater then the last month i.e 1st of march 2020 but the output is giving me users till 1 april, why not till today i.e 11 april, the data is in following format
"_id" : ObjectId("1dv47sd1a10048521sa1234d"),
"updatedAt" : ISODate("2020-04-01T16:19:26.460+05:30"),
"createdAt" : ISODate("2020-04-01T16:18:46.066+05:30"),
"email" : "edx#gmail.com",
"phone" : "xxxxxxxxxx",
"password" : "$awdad$2b$10$4YaO6AEZqXA9ba0iz14ALi",
"dob" : "00/20/1990",
"stripeID" : "xxxxxxxxxxxxxxxx",
"__t" : "Customer",
"banned" : false,
"picture" : "link to image",
"name" : {
"first" : "ababab",
"last" : "Saaa"
},
"orderCount" : 2,
"creditCards" : [ ],
"addresses" : [ ],
"__v" : 0,
"isEmailVerified" : true
i have written a query for extracting data from the date greater then last month but it is giving me data till the 1 of april, my query is as follows
db.users.find({
"createdAt" : { "$gte" :new Date("2020-03-1") }
})
so i want to get data timm today from 1 march 2020 also order count is greter then 1,thanks in advance i am preety new with mongo
MongoDB only stores absolute times (aka timestamps or datetimes), not dates. As such the queries should generally be specified using times, not dates, also.
Furthermore, MongoDB always stores times in UTC. Different systems can operate in different timezones. For example, the shell may be operating in a different timezone from your application.
To query using dates:
Determine what timezone the dates are in.
Convert dates to times in that timezone. For example, 2020-03-01 00:00:00 UTC - 2020-03-31 23:59:59 UTC and 2020-03-01 00:00:00 -0400 - 2020-03-31 23:59:59 -0400 are both "March" and would match different sets of documents.
Convert the times to UTC. This may be something that a framework or library you are using handles for you, for example Mongoid in Ruby does this.
Use the UTC times to construct MongoDB queries.
This is stated in the documentation here.

Fetch documents from a MongoDB collection based on timestamp

I have a MongoDB collection with documents that look like this
{
"_id" : ObjectId("5aab91b2caa256021558f3d2"),
"Timestamp" : "2017-11-16T14:43:07.5357785+01:00",
"status" : 1,
"created_at" : 1521193394,
"updated_at" : 1521193394,
"deleted_at" : ""
}
Data gets entered into the collection every 15 minutes. Using the created_at field, which is in epoch time, I would like to find a way to fetch data at the top of every hour. So for example, data is entered at 12.00 12.15 12.30 12.45 13.00 13.15 13.30 13.45 14.00.
I would like to fetch entries from the collection that were entered at 12.00 13.00 and 14.00.
I am also open to suggestions as to whether or not using epoch time is the best way to go about it.
Using epoch time is really a good way to go.
Since you are stoing in seconds, every round hour can be divisible by 3600(seconds in hours) without remainder. You can make use of this property to find your documents.
db.collection.find({created_at: {$mod: [ 3600, 0 ]}});
According to $mod documentation, it will,
Select documents where the value of a field divided by a divisor has
the specified remainder
We provided divisor as 3600 and remainder as 0. This should give what you expect.
To ignore seconds:
For this condition, mod(epoch, 3600) should be less than 59. This query can be formed using $expr of mongo 3.6
db.collection.find({$expr: {$lte: [{ $mod: [ '$created_at', 3600 ] }, 59]}});
Hope this helps!

MongoDB query to retrieve distinct documents by date

I have documents in the database with a dateTime value like so:
{
"_id" : ObjectId("5a66fa22d29dbd0001521023"),
"exportSuccessful" : true,
"month" : 0,
"week" : 4,
"weekDay" : "Mon",
"dateTime" : ISODate("2018-01-22T09:02:26.525Z"),
"__v" : 0
}
I'd like to:
query the database for a given date and have it return the document that contains the dateTime if the date matches (I don't care about the time). This is mainly to test before inserting a document that there isn't already one for this date. In the above example, if my given date is 2018-01-22 I'd like the document to be returned.
retrieve all documents with a distinct date from the database (again, I don't care about the time portion). If there are two documents with the same date (but different times), just return the first one.
From what I understand Mongo's ISODate type does not allow me to store only a date, it will always have to be a dateTime value. And on my side, I don't have control over what goes in the database.
Try range query with start date time from start of the day to end date time to end of the day. So basically create dates a day apart.
Something like
var start = moment().utc().startOf('day');
var end = moment().utc().endOf('day');
db.collection.find({
dateTime: {
$gte: start,
$lte: end
}
})
Get all distinct dates documents:
db.collection.aggregate(
{"$group":{
"_id":{
"$dateToString":{"format":"%Y-%m-%d","date":"$dateTime"}
},
"first":{
"$first":"$$ROOT"
}
}}])

How to write Mongo query to find video details between two dates

In My mongodb there is a video collection in which there is a creationTime list like following and i want to fetch the record between any two dates by using creationTime.
"creationTime" : {
"logtime" : ISODate("2013-08-12T10:54:44.914Z"),
"logtimeStr" : "12-08-2013 04:24:44",
"day" : 12,
"month" : 8,
"year" : 2013,
"hour" : 16,
"min" : 24,
"second" : 44
}
A little bit nicer way to write a range query, and also just mentioning that $and is implicit within MongoDB and only needs to be used in specific cases that actually require it:
db.collection.find({
"creationTime.logtime": {
"$gt": new Date("2014-08-01"), "$lt" new Date("2014-08-13")
}
})
At least that is the theory for a range query. But currently you have a really big problem and that is your dates are actually being stored as strings.
This is a huge problem as basically when these are strings ( and especially as they are currently formatted ) then you are stuck with a lexical comparison of strings, and the strings you have to not lexically compare properly in the sense of one being "greater" in value than the other.
Strings would need to be presented in the order of "year" then "month" then "day", and with two digit representations in order to match a lexical comparison. What you have currently does not.
But do not change the strings, change them to proper date types and then the query as shown will actually work correctly.
Use Mongodb comparison operators $lt and $gt ( or $lte & $gte for inclusive limits )
How you create START_DATE and END_DATE depends on language you are using .e.g. for javascript you would use new Date()
db.myVideoCollection.find({
'$and':[
{'$creationTime.logtime':{'$gt':START_DATE },
{'$creationTime.logtime':{'$lt':END_DATE }
]
})

MongoDB Aggregation Framework Date NOW

I am attempting to perform a calculation in an aggregation based on the day of the current month. For example, I want to divide the total number of transactions by the day of the month to get transactions per day.
The problem is I can't figure out how to get the current date. I see plenty of examples where it's hardcoded, but what I need is more like the MySQL NOW() function.
I've tried something like this:
> db.statistics.aggregate([{$project: {dayofmonth: {$dayOfMonth: Date()}}}])
{
"errmsg" : "exception: can't convert from BSON type String to Date",
"code" : 16006,
"ok" : 0
}
But that produces the error you see.
How can I get the current day of the current month for use in an aggregation calculation?
You almost did it. You have to write new Date()
db.statistics.aggregate([
{$project: {dayofmonth: {$dayOfMonth: new Date()}}}
])
it will produce results like this:
{
"result" : [
{
"_id" : "statisctiId",
"dayofmonth" : 9
}
}