Timestamp и ObjectId в mongoDB
У каждой записи в mongoDB есть поле _id
, которое должно быть уникальным в коллекции.
По умолчанию тип этого поля - ObjectId, и оно присваивается автоматически, если поле не заполнено при сохранении.
Давайте рассмотрим, что из себя представляет тип ObjectId.
Это 12 байт, которые состоят из:
- 4 байта, содержащие количество секунд с начала Unix эпохи
- 3 байта, содержащие идентификатор устройства
- 2 байта, содержащие id процесса
- 3 байта, содержащие счетчик, который стартует со случайного значения
Как видим, первые 4 байта содержат дату создания, и ее можно использовать:
- Сортируя по полю
_id
мы получаем документы в порядке их создания - Мы можем получить время создания документа, имея только поле
_id
.
Но надо иметь в виду, что эта дата создания доступна с точностью до секунды. Если два документа созданы в течение одной секунды, то их порядок при сортировке по _id
не определен.
Т.о. если нам достаточна секундная точность, то можем НЕ создавать поля наподобие created_at
:
{
created_at: ISODate("2015-01-18T12:07:47.036Z")
// остальные поля
}
т.к. дата создания содержится в поле _id
.
Получение даты из ObjectId
В mongoDB shell дату можно получить с помощью метода getTimestamp():
> db.users.findOne()._id.getTimestamp()
ISODate("2015-01-18T09:07:47Z")
А в коде питона - с помощью аттрибута generation_time
>>> from pymongo import MongoClient
>>> db = MongoClient().db_name
>>> user = db.users.find_one()
>>> user['_id'].generation_time
datetime.datetime(2015, 1, 18, 9, 7, 47, tzinfo=<bson.tz_util.FixedOffset object at 0x10e758d50>)
Дата возвращается в UTC, причем в питоне это aware datetime c таймзоной.
На всякий случай, в этих примерах я использовал такие версии:
- mongoDB v2.6.6
- pymongo v2.7.2
P.S. спасибо @eugeneglybin за наводку.