MongoDB: Migrate some YYYY-MM-DD dates to ISO 8601 - mongodb

I have a field with dates stored in different formats (due to a code change at some point):
Some documents in the same collection use ISO 8601 ("2022-06-27T00:00:00.000Z"), while some others use the YYYY-MM-DD syntax ("2022-06-27").
This is a problem, because this query fails to fetch the YYYY-MM-DD documents (while it does fetch the ISO ones):
filter:
{"where":{"and":[{"notificationOfNeedDate":{"gte":"2019-04-08T21:00:00.000Z"}}]},"order":["aCode DESC"],"limit":24,"skip":0}
I believe the solution is to migrate all YYYY-MM-DD to ISO dates
Is there a command to run in mongodb in order to "UPDATE" all YYYY-MM-DD to ISO dates (for that collection and field), respecting the locale timezone offset and the DST settings for that day?
Thanks

Another example why date values should never be stored as string, it's a design flaw. Store always proper Date objects, so you go in the right direction.
Your question is not really clear, string "YYYY-MM-DD" is also a valid format according to ISO 8601 (a date, just without time information).
You can use $dateFromString:
db.collection.updateMany(
{ timestamp: { $type: "string" } },
[ {
$set: {
notificationOfNeedDate: {
$dateFromString: {
dateString: '$notificationOfNeedDate',
timezone: 'Europe/Athens'
}
}
}
} ]
)
You don't need to specify format, because ISO-8601 format is the default.
Then in your query you need to filter also on Date values:
db.collection.find({ notificationOfNeedDate: { $gte: ISODate("2019-04-08T21:00:00.000Z") } })
Of course, ISODate("2019-04-09T00:00:00+03:00") works also

Related

Date conversion in Mongo Db

I am having trouble converting "7/26/2020 18:34:25" into any date format from which Mongo can run aggregate operation.
The date in the Mongo is stored as string.
I have tried "$toDate", "$convert" and "$dateToString".
You need to use $dateFromString
$project: {
date: {
$dateFromString: {
dateString: '$dateFieldName',
format: '%m/%d/%Y %H:%M:%S'
}
}
}
playground
Try using Moment Library for converting you date
In your case this code can help you:
moment('7/26/2020 18:34:25').toDate();
You can test this code on browser side on this page
enter link description here

Timezone query on MongoDB

I'm building an application wherein users can be located in various timezones, and the queries I run are sensitive to their timezones.
The problem I'm having is that MongoDB seems to be ignoring the timezone on query time!
This is an example of a date field "2019-09-29T23:52:13.495000+13:00", here's the full json:
And this is an example of a query:
{
"at": {
"$gte": "2019-09-29T00:00:00+00:00",
"$lte": "2019-09-30T00:00:00+00:00"
}
}
All of my dates are saved either with +12 or +13 because those are the timezones where my customers are at the moment, essentially what that means for the above query is that I should be seeing some results from the 2019-10-01:00:00:00+13:00 due to the first of October still being the 30th of September in UTC, and I'm not.
I'm new to this and not too far down the rabbit hole so I'm open to refactoring/change of thinking if it will make things easier.
For context, in case it makes a difference I'm using PyMongo, and my MongoDB version is 4.2
EDIT!
I've tried converting the "at" field into date, but the timezone seem to have been suppressed or is not visible
With that I also had to change the way I query
{ "at": {
"$gte": ISODate("2019-09-29T00:00:00+00:00"),
"$lte": ISODate("2019-09-30T00:00:00+00:00")
}
}
Didn't help
MongoDB uses the UTC timezone when it stores date. Using your example date:
> ISODate("2019-09-29T23:52:13.495000+13:00")
ISODate("2019-09-29T10:52:13.495Z")
So the +13:00 timezone is converted to Z (UTC) timezone by ISODate(), and this is the value stored in the database.
> db.test.insert({_id:0, at: ISODate("2019-09-29T23:52:13.495000+13:00")})
> db.test.find()
{ "_id" : 0, "at" : ISODate("2019-09-29T10:52:13.495Z") }
Note that "at" is stored in UTC time instead of +13 as inserted.
Querying using ISODate() as per your example works as expected:
> db.test.find({ "at": {
... "$gte": ISODate("2019-09-29T00:00:00+00:00"),
... "$lte": ISODate("2019-09-30T00:00:00+00:00")
... }
... })
{ "_id" : 0, "at" : ISODate("2019-09-29T10:52:13.495Z") }
The timezone information is not visible due to the visual tool you're using. It is visible in the mongo shell as Z, as in the above example.
The advantage of storing UTC is that you can convert them to any other timezones without worrying about daylight saving time. There are date specific aggregation operators that deals with timezones and convert between them. See Date Expression Operators and https://stackoverflow.com/a/48535842/5619724 for examples.

I can not get dates after my current date

I want to obtain the records that the "FECHA_FIN" field is greater than or equal to today's date.
this is an example of my data:
but with this query:
db.getCollection('susp_programadas').find( {"FECHA_FIN":{ $gte: new Date("YYYY-mm-dd") }} )
I do not get results, what am I doing wrong? Thank you
You can convert the date to an ISO date and query that way. Since you stored the date as a string mongo has no idea how to query it against an ISO date without conversion.
If you stored your date in mongo as the default ISO date then you could have easily done this:
db.getCollection('susp_programadas').find({"FECHA_FIN":{$gte: new Date()}})
So this is how you can do it now:
db.getCollection('susp_programadas').aggregate([
{
$project: {
date: { $dateFromString: { dateString: '$FECHA_FIN' }}
}
},
{ $match: { date: { $gte: new Date() }}}
])
You can use the $dateFromString in an aggregate query with a $match to get the results you want. Note that $dateFromString is only available in MongoDB version 3.6 and up.
If there is no way to convert your data to ISODate or upgrade your DB you could also consider another solution which via $where:
db.getCollection('susp_programadas').find({
$where: function(){
return new Date(this.FECHA_FIN) > Date.now()
}
})
However that solution suffers from the fact that $where can not use indexes so have that in mind.

How to convert a date stored as string in MongoDB to ISODate?

I have a collection in which each document has a time field with value stored as similar to "21-Dec-2017".
I want to convert this to ISODate using projection.
My Query:
db.getCollection('orders').aggregate([{
$project:{time : {$add : new Date("$time")}}
}])
But this is returning me ISODate("1970-01-01T00:00:00.000Z") always.
you can try this,
db.getCollection('orders').aggregate([{
$project: {
time: {
$dateToString: {
format: "%d-%m-%G",
date: new Date("$time")
}
}
}
}
])
there is no any string function to get months name eg.Jan,Feb..Dec.
but you can refer https://docs.mongodb.com/manual/reference/operator/aggregation/dateToString/
to more information.
There is no problem in this ISODate("1970-01-01T00:00:00.000Z") format.
you should store date in ISO format but change format on client side according to you.
Basically you want to show date in dd/mm/yy format.
You can use http://momentjs.com/ to show date according to you.

find document in today's date range in mongodb

I have a collection, Plans. I want to find everything within the range of one month. Here is a sample of what the data could look like:
{
"_id": "someid",
"dateStart": ISODate("2015-03-01T00:00:00Z"),
"dateEnd": ISODate("2015-03-31T00:00:00Z"),
"items": [
"someotherid"
]
}
How can I find the Plan such that today's date is between dateStart and dateEnd?
To find a Plan such that today's date is between the dateStart and dateEnd fields, create a date object that holds the current date then use the $lt and $gt query operators on the date fields to query documents where today's date falls between the two fields:
currentDate = new Date();
Plans.find({
dateStart: { $lt: currentDate },
dateEnd: { $gt: currentDate }
});
date1 = new Date('3/1/15');
date2 = new Date('4/1/15');
Plans.find({
startDate: {$gte: date1},
endDate: {$lt: date2}
});
New Date objects initialize to 00:00:000 so you can use that to your advantage here. Also note that "less than 4/1" is equivalent to "less than or equal to midnight on 3/31" - but the former is much easier to write.
Also note that moment is a super handy utility for doing manipulations like this. For example: moment().endOf('month').toDate()
To add the package just do:
$ meteor add momentjs:moment