In Mongodb, if I have an ISODate of "2021-07-29T01:57:49.075Z", how do I convert this value to the equivalent BSON timestamp value? The BSON value should be in the form of Timestamp(nnnnnnnnnn, 1). The n value is 10 digits long. I've seen a close answer using the $toLong aggregate, but the long number returned doesn't fit into the 10 digits.
Also the reverse, how to convert a BSON timestamp value to an ISODate.
This seems so simple but I can't find any reference and similar questions convert to a long number not a BSON timestamp in the form described above.
Thanks for your help.
Related
Let's say I have an date attribute stored in the format dd/MM/YYYY HH:mm:ss i.e. 22/12/2021 10:15:23. Now I just want 22/12/2021 as a date value so that I can do date comparisons. I want this operation to happen at database itself so that I can do date comparisons as part of the query/aggregation itself. Please note I am using Spring MongoDB driver.
Getting date alone from a datetime string is not possible in MongoDB since it always returns an ISO date with time. As a workaround we can convert the time HH:mm:ss to 00:00:00 either by applying String operations on the string attribute or by using Arithmetic operations on the date. We will have to add a temporary field in the query which will hold the converted value using add field operations. And then we can compare them with a given date.
If at some time, the epoch is ffffffff, than the objectId created at this moment is something like :
ffffffff15580625bcb65364
Then, what could be the ObjectId created after 1 second?
Then, what could be the ObjectId created after [the Unix epoch rolls over in 32 bits]?
This would depend on the specific implementation, its programming language and their handling of math calculations.
It is possible that some implementations and languages would error when they retrieve the number of seconds since the Unix epoch as a 64-bit integer (which is quite common today) and then try to use a value which exceeds 32 bits in size for ObjectId generation. If this happens the driver will cease to be able to generate ObjectIds, consequently it may be unable to insert documents without _id values being provided by the application using some other generation strategy.
In other implementations the timestamp itself may roll over to zero, at which point the ObjectId generation will succeed with a very small timestamp value.
Yet other implementations may truncate (from either most or least significant side) the timestamp to coerce it into the 32 available bits of an ObjectId.
The ObjectId value itself doesn't actually have to have an accurate timestamp - it is required to be unique within the collection and it is "generally increasing" but MongoDB-the-database wouldn't care if ObjectId values wrapped to around zero at some point.
As docs says, timestamp is represented by 4-byte.
4-byte timestamp value, representing the ObjectId’s creation, measured in seconds since the Unix epoch
4 bytes is from -2,147,483,648 to 2,147,483,647 values, so, that is 4,294,967,295 values.
And the date from 4,294,967,295 according to unix timestamp is: GMT: Sunday, 7 February 2106 6:28:15
After this date, ObjectId won't be able to store the timestamp.
So, can ObjectId overflow? In 85 years every new ObjectId created will fail because it won't be able to create the timestamp with only 4 bytes.
I already have a SO question and answer on how to convert BSON Timestamp in a MongoDB aggregation, but now I have a situation where I would like to convert in node.js.
So just to repeat. My goal is to convert a "Timestamp" datatype to a javascript date, without doing it in an aggregation - is this possible?
If the BSON library you are using provides Timestamp type, you can use its getTime method to return the seconds, and create a date from that:
Date(object.clusterTime.getTime())
If you don't have that function available, the timestamp is a 64-bit value where the high 32-bits are the seconds since epoch, and the low 32-bits are a counter.
Bitshift the value 32 bits right or divide by 2^32 to get the seconds:
Date(object.clusterTime/Math.pow(2,32))
I want to use timestamp value as an integer value i.e. the total number of seconds/milliseconds (the converted timestamp value into seconds/milliseconds) and use it with $divide accumulator/operator
I tried that as this code but get error
pymongo.errors.OperationFailure: $divide only supports numeric types, not date and int
I google for convert datetime to int though get little helpful result
So how can we get around it i.e. to get $divide work with timestamp?
I know that we can use getTimestamp() to retrieve the timestamp from the ObjectId, but is there any way to generate an ObjectId from a timestamp?
More specifically, if I have an input of month and year, then I want to convert it into Mongo ObjectID to query in db, how should I do this?
try this,
> ObjectId("5a682326bf8380e6e6584ba5").getTimestamp()
ISODate("2018-01-24T06:09:42Z")
> ObjectId.fromDate(ISODate("2018-01-24T06:09:42Z"))
ObjectId("5a6823260000000000000000")
Works from mongo shell.
If you pass a number to the bson ObjectId constructor it will take that as a timestamp and pass it to the generate method.
You can get a Date from a month and year per this answer (months start at zero).
So:
timestamp = ~~(new Date(2016, 11, 17) / 1000)
new ObjectId(timestamp)
Yes you can:
dummy_id = ObjectId.from_datetime(gen_time)
Where gen_time is datetime.
An ObjectId() is a 12-byte BSON type and consists of:
The first 4 bytes representing the seconds since the unix epoch
The next 3 bytes are the machine identifier
The next 2 bytes consists of process id
The last 3 bytes are a random counter value
Clearly, you will not be able to create ObjectId() only from timestamp.