kefeizhou
kefeizhou

Reputation: 6552

uses for mongodb ObjectId creation time

The ObjectId used as the default key in mongodb documents has embedded timestamp (calling objectid.generation_time returns a datetime object). So it is possible to use this generation time instead of keeping a separate creation timestamp? How will you be able to sort by creation time or query for the last N items efficiently using this embedded timestamp?

Upvotes: 69

Views: 71305

Answers (7)

hamx0r
hamx0r

Reputation: 4278

For those wanting to truly use ObjectId for datetime, and not just rely on the fact that ObjectId's are always increasing over time and can therefore be used to order documents by creation time indirection, then here's how:

One can create their filter criteria to return documents whose IDs were made in some datetime range (in Python) by making a dummy ObjectID.from_datetime() like so:

# gets docs which were created in last 5 minutes
resp = await collection.update_one({'_id': {'$gte': ObjectId.from_datetime(datetime.utcnow() - timedelta(minutes=5))}},

Upvotes: 1

Chen Dachao
Chen Dachao

Reputation: 1836

To query projects created within 7 days, I use below snippet:

db.getCollection('projects').find({
  $where: function() {
    // last 7 days
    return Date.now() - this._id.getTimestamp() < (7 * 24 * 60 * 60 * 1000)
  }
}).sort({
  '_id': -1
})

and if you want to get items with specified fields:

db.getCollection('projects').find({
  $where: function() {
    // last 7 days
    return Date.now() - this._id.getTimestamp() < (7 * 24 * 60 * 60 * 1000)
  }
}).sort({
  '_id': -1
}).toArray().map(function(item) {
  var res = {};
  res['Project Name'] = item.config.label;
  res['Author'] = item.author;
  res['Created At'] = item._id.getTimestamp().toLocaleDateString();
  res['Last Modified Date'] = item.config.lastModifDate.toLocaleString();
  return res;
});

it will return something like this:

[{
  "Project Name": "Newsletter",
  "Author": "larry.chen",
  "Created At": "Thursday, January 19, 2017",
  "Last Modified Date": "Thursday, January 19, 2017 17:05:40"
}...]

PS: the software I use to connect to MongoDB is Robo 3T

Hope this will help you.

Upvotes: 1

wprl
wprl

Reputation: 25447

From: http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-DocumentTimestamps

"sorting on an _id field that stores ObjectId values is roughly equivalent to sorting by creation time, although this relationship is not strict with ObjectId values generated on multiple systems within a single second."

Upvotes: 3

Andrew Orsich
Andrew Orsich

Reputation: 53705

I suppose since MongoDB ObjectId contain a timestamp, you can sort by 'created date' if you will sort by objectId:

items.find.sort( [['_id', -1]] ) // get all items desc by created date.

And if you want last 30 created items you can use following query:

items.find.sort( [['_id', -1]] ).limit(30) // get last 30 createad items 

I am actualy not sure,i just suppose that ordering by _id should work as described above. I'll create some tests later.

Update:

Yes it is so. If you order by _id you will automatically order by _id created date. I've done small test in c#, mb someone interest in it:

  public class Item
  {
    [BsonId]
    public ObjectId Id { get; set; }

    public DateTime CreatedDate { get; set; }

    public int Index { get; set; }
  }



 [TestMethod]
 public void IdSortingTest()
 {
   var server = MongoServer.Create("mongodb://localhost:27020");
   var database = server.GetDatabase("tesdb");

   var collection = database.GetCollection("idSortTest");
   collection.RemoveAll();

   for (int i = 0; i <= 500; i++)
   {
     collection.Insert(new Item() { 
             Id = ObjectId.GenerateNewId(), 
             CreatedDate = DateTime.Now, 
             Index = i });
   }

   var cursor = collection.FindAllAs<Item>();
   cursor.SetSortOrder(SortBy.Descending("_id"));
   var itemsOrderedById = cursor.ToList();

   var cursor2 = collection.FindAllAs<Item>();
   cursor2.SetSortOrder(SortBy.Descending("CreatedDate"));
   var itemsOrderedCreatedDate = cursor.ToList();

   for (int i = 0; i <= 500; i++)
   {
     Assert.AreEqual(itemsOrderedById[i].Index, itemsOrderedCreatedDate[i].Index);
   }
}

Upvotes: 105

DanH
DanH

Reputation: 3802

The code to convert a DateTime to its corresponding timestamp with the c# driver is as follows:

    public static ObjectId ToObjectId(this DateTime dateTime)
    {
        var timestamp = (int)(dateTime - BsonConstants.UnixEpoch).TotalSeconds;
        return new ObjectId(timestamp, 0, 0, 0);
    }

More info here: http://www.danharman.net/2011/10/26/mongodb-ninjitsu-using-objectid-as-a-timestamp/

Upvotes: 3

user105991
user105991

Reputation: 541

Yes, you can use the generation_time of BSON ObjectId for the purposes you want. So,

db.collection.find().sort({ _id : -1 }).limit(10)

will return the last 10 created items. However, since the embedded timestamps have a one second precision, multiple items within any second are stored in the order of their creation.

Upvotes: 25

user2665694
user2665694

Reputation:

See

http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-DocumentTimestamps

Likely doable however I would always prefer having a dedicated timestamp instead of relying on some such internals like timestamp somehow embedded in some object id.

Upvotes: 1

Related Questions