Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I query MongoDB ObjectId by date?

People also ask

Is MongoDB ObjectId ordered?

No. Since ObjectIDs are typically generated on the client, the deployment topology does not factor into the ordering of ObjectIDs. Even if the ObjectIDs are generated on the server, multiple ObjectIDs generated in the same second will not have a predictable ordering.

How does MongoDB ObjectId work?

ObjectID is automatically generated by the database drivers, and will be assigned to the _id field of each document. ObjectID can be considered globally unique for all practical purposes. ObjectID encodes the timestamp of its creation time, which may be used for queries or to sort by creation time.


Popping Timestamps into ObjectIds covers queries based on dates embedded in the ObjectId in great detail.

Briefly in JavaScript code:

/* This function returns an ObjectId embedded with a given datetime */
/* Accepts both Date object and string input */

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 = ObjectId(hexSeconds + "0000000000000000");

    return constructedObjectId
}


/* Find all documents created after midnight on May 25th, 1980 */
db.mycollection.find({ _id: { $gt: objectIdWithTimestamp('1980/05/25') } });

In pymongo, it can be done this way:

import datetime
from bson.objectid import ObjectId
mins = 15
gen_time = datetime.datetime.today() - datetime.timedelta(mins=mins) 
dummy_id = ObjectId.from_datetime(gen_time)
result = list(db.coll.find({"_id": {"$gte": dummy_id}}))

Using inbuilt function provided by mongodb drivers in in Node.js lets you query by any timestamp:

var timestamp = Date.now();
var objectId = ObjectID.createFromTime(timestamp / 1000);

Alternatively, to search for records before the current time, you can simply do:

var objectId = new ObjectID(); // or ObjectId in the mongo shell

Source: http://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html


You can use $convert function to extract the date from ObjectId starting in 4.0 version.

Something like

$convert: { input: "$_id", to: "date" } 

You can query on date comparing between start and end time for date.

db.collectionname.find({
  "$expr":{
    "$and":[
      {"$gte":[{"$convert":{"input":"$_id","to":"date"}}, ISODate("2018-07-03T00:00:00.000Z")]},
      {"$lte":[{"$convert":{"input":"$_id","to":"date"}}, ISODate("2018-07-03T11:59:59.999Z")]}
    ]
  }
})

OR

You can use shorthand $toDate to achieve the same.

db.collectionname.find({
  "$expr":{
    "$and":[
      {"$gte":[{"$toDate":"$_id"}, ISODate("2018-07-03T00:00:00.000Z")]},
      {"$lte":[{"$toDate":"$_id"},ISODate("2018-07-03T11:59:59.999Z")]}
    ]
  }
})

how to find Find the Command (this date[2015-1-12] to this Date[2015-1-15]):

db.collection.find({
  _id: {
    $gt: ObjectId(Math.floor((new Date('2015/1/12'))/1000).toString(16) + "0000000000000000"), 
    $lt: ObjectId(Math.floor((new Date('2015/1/15'))/1000).toString(16) + "0000000000000000")
  }
}).pretty()

Count the Command (this date[2015-1-12] to this Date[2015-1-15]):

db.collection.count({
  _id: {
    $gt: ObjectId(Math.floor((new Date('2015/1/12'))/1000).toString(16) + "0000000000000000"), 
    $lt: ObjectId(Math.floor((new Date('2015/1/15'))/1000).toString(16) + "0000000000000000")
  }
})

Remove the Command (this date[2015-1-12] to this Date[2015-1-15]):

db.collection.remove({
  _id: {
    $gt: ObjectId(Math.floor((new Date('2015/1/12'))/1000).toString(16) + "0000000000000000"), 
    $lt: ObjectId(Math.floor((new Date('2015/1/15'))/1000).toString(16) + "0000000000000000")
  }
})

Since the first 4 bytes of an ObjectId represent a timestamp, to query your collection chronologically, simply order by id:

# oldest first; use pymongo.DESCENDING for most recent first
items = db.your_collection.find().sort("_id", pymongo.ASCENDING)

After you get the documents, you can get the ObjectId's generation time like so:

id = some_object_id
generation_time = id.generation_time