В прошлом уроке каждая вставка возвращала _id. Когда мы задавали его сами, это было наше число, когда нет, MongoDB придумывала что-то вроде ObjectId('6ac9371c7c7353d2ce52946e'). Сегодня разбираемся, зачем документу это поле, из чего состоит такой номер и когда его стоит выбирать самому.
Номерок в гардеробе
В гардеробе театра пальто никто не ищет по цвету или фасону. Тебе дают номерок, и по нему пальто находят за секунду. Двух одинаковых номерков в одном гардеробе не бывает.
У каждого документа в MongoDB есть такой номерок, поле _id. Три правила:
- поле есть всегда: если ты его не указал, MongoDB добавит его сама;
- значение уникально внутри коллекции: второй документ с тем же
_idне вставится; - по
_idвсегда есть индекс, поэтому поиск по нему быстрый.
В терминах реляционной теории _id это первичный ключ, только с фиксированным именем.
Что внутри ObjectId
Если _id не указан, MongoDB подставляет значение типа ObjectId. Это 12 байт, которые печатаются как 24 шестнадцатеричные цифры. Возьмём номер и разрежем его:
66f8a1c2 e4b0a1b2c3 d4e5f6
└──┬───┘ └───┬────┘ └─┬──┘
время случайное счётчик
4 байта 5 байт 3 байта
- Время. Первые 4 байта это момент создания в секундах от 1970 года.
- Случайное значение. 5 байт генерируются один раз на процесс, чтобы два сервера не выдали одинаковых номеров.
- Счётчик. 3 байта растут на единицу с каждым новым номером внутри процесса.
Из-за этой раскладки номер можно получить без обращения к базе и без согласования с другими серверами: каждый, кто создаёт документ, придумывает номер сам, и номера не совпадут. Обычно ObjectId генерирует даже не сервер, а драйвер в приложении.
Время создания можно достать прямо из номера:
const id = ObjectId('66f8a1c2e4b0a1b2c3d4e5f6')
id.getTimestamp()
id.toString()
ISODate('2024-09-29T00:39:30.000Z')
66f8a1c2e4b0a1b2c3d4e5f6
Отсюда полезное следствие: документы, вставленные позже, обычно получают номера больше. Сортировка по _id примерно совпадает с сортировкой по времени создания. Примерно, потому что внутри одной секунды порядок решает счётчик, а у разных процессов счётчики свои.
Время в ObjectId записано в секундах. Если нужно точное время события, храни его отдельным полем, например created_at, как в заказах учебной базы.
урок из курса
Урок из курса «MongoDB с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.