Поле _id и тип ObjectId

Первичный ключ каждого документа: что такое ObjectId и когда стоит назначать _id вручную.

Каждый документ обязан иметь уникальное поле _id — это его первичный ключ. Если вы его не задали, MongoDB подставит значение типа ObjectId.

_id есть всегда

В MongoDB нет документа без _id. Это поле уникально в пределах коллекции и автоматически индексируется, поэтому поиск по нему очень быстрый. По сути это аналог PRIMARY KEY из реляционных баз — только обязательный и встроенный.

Как устроен ObjectId

Значение по умолчанию — ObjectId, 12-байтовый идентификатор. Он не случаен, в нём закодированы:

  • 4 байта — время создания (Unix-время в секундах);
  • 5 байт — случайное значение, уникальное для процесса/машины;
  • 3 байта — инкрементирующий счётчик.

Такая конструкция даёт два приятных свойства: идентификаторы практически не сталкиваются даже на разных серверах (важно при шардировании), и они примерно отсортированы по времени — более новые документы имеют большие ObjectId. Из ObjectId даже можно достать дату создания:

const id = ObjectId("652f1a2b3c4d5e6f7a8b9c0d");
id.getTimestamp();   // вернёт Date создания документа

Свой собственный _id

Вы не обязаны использовать ObjectId. Если у сущности есть естественный уникальный ключ — артикул товара, email, код страны — можно задать _id самому:

db.products.insertOne({
  _id: "SKU-1001",
  name: "Кофе",
  price: 450
})

Теперь поиск по артикулу — это поиск по первичному ключу, самый быстрый из возможных. Но помните: _id уникален, и повторная вставка с тем же значением даст ошибку дубликата.

Результат:

{
  "errmsg": "E11000 duplicate key error",
  "code": 11000
}

Что использовать

Если естественного ключа нет — оставьте ObjectId по умолчанию, это надёжно и удобно. Если есть стабильный бизнес-идентификатор, который точно не меняется, — задавайте его сами: запросы по нему станут проще и быстрее. Менять _id у существующего документа нельзя, поэтому выбирайте то, что не будет меняться.

Итог

  • _id — обязательный уникальный первичный ключ, индексируется автоматически.
  • ObjectId кодирует время создания, что даёт уникальность и приблизительную сортировку по времени.
  • Можно задать собственный _id; повтор значения вызовет ошибку дубликата (E11000).
Проверьте себя
1. Может ли документ в MongoDB не иметь поля _id?
AДа, оно необязательно
BНет, _id есть у каждого документа; если не задан — генерируется автоматически
CТолько в коллекциях без индексов
DТолько если документ пустой
2. Что закодировано в первых байтах ObjectId?
AИмя коллекции
BВремя создания документа
CРазмер документа
DВерсия MongoDB
3. Что произойдёт при вставке документа с уже существующим _id?
AСтарый документ перезапишется
BВозникнет ошибка дубликата ключа (E11000)
CMongoDB изменит _id на новый
DДокументы объединятся
Поддержать проект