Date format in Mongo DB is wrong - mongodb

In Database the date format stored is as below. Adding two same fields but values are different.
packageDeliveredTime : 2020-08-21 2:39:37
packageDeliveredTime : 2020-08-21 09:3:45
Due to the the above format few of the API's and database query's are not filtering the data correctly and like this there is so many records that got stored in the data base.
The above date format needs to get updated as below.
packageDeliveredTime : 2020-08-21 02:39:37
packageDeliveredTime : 2020-08-21 09:03:45

You should never store date/time values as string, it's a design flaw. Store always proper Date objects.
In order to convert the strings to date function $dateFromString is not sufficient. You can use moment.js library to do this:
db.collection.find({ packageDeliveredTime: { $exists: true, $type: "string" } }).forEach(function (doc) {
db.collection.updateOne(
{ _id: doc._id },
{ $set: { packageDeliveredTime: moment(doc.packageDeliveredTime).toDate() } }
);
})

Related

How to convert BSON Timestamp from Mongo changestream to a date?

I am getting started with the Changestream in Mongo. In my current setup a stitch functions inserts the changelog events into a revision collection. However when I read data from the collection, I can't convert the Timestamp fields. I have tried with the following 2 attempts:
1) A pipeline
[
{
$match: {
'documentKey._id': _id,
},
},
{
$sort: { _id: -1 },
},
{
$addFields: {
convertedDate: { $toDate: 'clusterTime' },
},
},
]
But it gives the error: Error parsing date string 'clusterTime'; 0: passing a time zone identifier as part of the string is not allowed 'c'; 6: Double timezone specification 'r'
2) The bson Timestamp class
import { Timestamp } from 'bson';
const asTimestampInstance = new Timestamp(v.clusterTime);
But here typescript gives me the error: Expected 2 arguments, but got 1.ts(2554)
index.d.ts(210, 30): An argument for 'high' was not provided.
In Altas, the clustertime correctly looks like a timestamp:
I hope that I am just missing something simple :)
Unfortunately $toDate doesn't work with timestamps directly. At least not in v4.0.
The argument should be either a number, a string, or an ObjectId.
You need to convert Timestamp to string first:
$addFields: {
convertedDate: { $toDate: {$dateToString:{date:"$clusterTime"}} },
},
2) The bson Timestamp class
You should take first 32-bit value from BSON's Timestamp class instance, it means seconds Epoch time, then multiply seconds on 1000 and make it milliseconds Epoch time, then call JS Date constructor.
If v is document from ChangeStream, v.clusterTime is BSON Timestamp class object. So, you should write:
const date = new Date(v.clusterTime.getHighBits() * 1000);
This example worked for me on MongoDB 4.0, ODM Mongoose 5.12, Node.js 12.

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 non-ISODate records in MongoDb

I have a Mongo collection that stored a date field as a string. I ran the query below to convert this field into an ISODate, but it failed. However, there are quite a few records that now show as an ISODate.
How do I query to find all documents that are an ISODate format and all documents that are still a string?
db.TestCollection.find({}).forEach(function(doc) {
doc.LastUpdated = new Date(doc.LastUpdated );
db.TestCollection.save(doc);
});
The original question has been answered, but the follow up question is: Is there a way to aggregate the type of data present in the column? I would like to return a count of each type of data in the column. I have seen type string and type date, but want to verify there isn't any other data types.
Here's roughly what I have tried:
db.TestCollection.aggregate([{
$project: {
LastUpdated : { $type: "$LastUpdated " }
}
}])

Mongo add timestamp field from existing date field

I currently have a collection with documents like the following:
{ foo: 'bar', timeCreated: ISODate("2012-06-28T06:51:48.374Z") }
I would now like to add a timestampCreated key to the documents in this collection, to make querying by time easier.
I was able to add the new column with an update and $set operation, and set the timestamp value but I appears to be setting the current timestamp using this:
db.reports.update({}, {
$set : {
timestampCreated : new Timestamp(new Date('$.timeCreated'), 0)
}
}, false, true);
I however have not been able to figure out a way to add this column and set it's value to the timestamp of the existing 'timeCreated' field.
Do a find for all the documents, limiting to just the id and timeCreated fields. Then loop over that and generate the timestampCreated value, and do an update on each.
Use updateMany() which can accept aggregate pipelines (starting from MongoDB 4.2) and thus take advantage of the $toLong operator which converts a Date into the number of milliseconds since the epoch.
Also use the $type query in the update filter to limit only documents with the timeCreated field and of Date type:
db.reports.updateMany(
{ 'timeCreated': {
'$exists': true,
'$type': 9
} },
[
{ '$set': {
'timestampCreated': { '$toLong': '$timeCreated' }
} }
]
)