1. Обзор
Иногда нам нужен идентификатор документа, который мы только что вставили в базу данных MongoDB . Например, мы можем захотеть отправить обратно идентификатор в качестве ответа вызывающей стороне или зарегистрировать созданный объект для отладки.
В этом руководстве мы увидим, как идентификаторы реализованы в MongoDB и как получить идентификатор документа, который мы только что вставили в коллекцию, с помощью программы на Java.
2. Что такое идентификатор документа MongoDB?
Как и в любой системе хранения данных, MongoDB нужен уникальный идентификатор для каждого документа, хранящегося в коллекции. Этот идентификатор эквивалентен первичному ключу в реляционных базах данных.
В MongoDB этот идентификатор состоит из 12 байтов:
- 4-байтовое значение временной метки представляет собой секунды, прошедшие с эпохи Unix.
- 5-байтовое случайное значение, сгенерированное один раз для каждого процесса. Это случайное значение уникально для машины и процесса.
- 3-байтовый инкрементный счетчик
Идентификатор хранится в поле с именем _id
и генерируется клиентом. Это означает, что идентификатор должен быть сгенерирован до отправки документа в базу данных. На стороне клиента мы можем либо использовать идентификатор, сгенерированный драйвером, либо сгенерировать собственный идентификатор.
Мы видим, что документы, созданные одним и тем же клиентом в одну и ту же секунду, будут иметь общие первые 9 байтов. Таким образом, уникальность идентификатора в этом случае зависит от счетчика. Счетчик позволяет клиенту создавать более 16 миллионов документов за одну секунду.
Хотя он начинается с метки времени, мы должны быть осторожны, чтобы идентификатор не использовался в качестве критерия сортировки. Это связано с тем, что документы, созданные в одну и ту же секунду, не обязательно будут отсортированы по дате создания, поскольку счетчик не может быть монотонным. Кроме того, разные клиенты могут иметь разные системные часы.
Драйвер Java использует для счетчика генератор случайных чисел, который не является монотонным. Вот почему мы не должны использовать идентификатор, сгенерированный драйвером, для сортировки по дате создания.
3. Класс ObjectId
Уникальный идентификатор хранится в классе ObjectId
, который предоставляет удобные методы для получения данных, хранящихся в идентификаторе, без их разбора вручную.
Например, вот как мы можем получить дату создания идентификатора:
Date creationDate = objectId.getDate();
Точно так же мы можем получить временную метку идентификатора в секундах:
int timestamp = objectId.getTimestamp();
Класс ObjectId
также предоставляет методы для получения счетчика, идентификатора машины или идентификатора процесса, но все они устарели.
4. Получение идентификатора
Главное помнить, что в MongoDB клиент генерирует уникальный идентификатор документа
перед его отправкой в кластер. Это отличается от последовательностей в реляционных базах данных. Это делает получение этого идентификатора довольно простым.
4.1. Идентификатор, сгенерированный водителем
Стандартный и простой способ создать уникальный идентификатор документа
— позволить драйверу выполнить эту работу. Когда мы вставляем новый документ
в коллекцию
, если в документе
нет поля _id
, драйвер генерирует новый ObjectId
перед отправкой команды вставки в кластер.
Наш код для вставки нового документа
в вашу коллекцию может выглядеть так:
Document document = new Document();
document.put("name", "Shubham");
document.put("company", "ForEach");
collection.insertOne(document);
Мы видим, что мы никогда не указываем, как должен быть сгенерирован идентификатор.
Когда метод insertOne()
возвращает значение, мы можем получить сгенерированный ObjectId
из документа
:
ObjectId objectId = document.getObjectId("_id");
Мы также можем получить ObjectId
как стандартное поле документа
, а затем привести его к ObjectId
:
ObjectId oId = (ObjectId) document.get("_id");
4.2. Пользовательский идентификатор
Другой способ получить идентификатор — сгенерировать его в нашем коде и поместить в документ
, как и любое другое поле. Если мы отправим документ
с полем _id
драйверу, он не сгенерирует новый.
Это может потребоваться в некоторых случаях, когда нам нужен идентификатор документа
MongoDB перед вставкой документа
в коллекцию
.
Мы можем сгенерировать новый ObjectId
, создав новый экземпляр класса:
ObjectId generatedId = new ObjectId();
Или мы также можем вызвать статический метод get() класса
ObjectId
:
ObjectId generatedId = ObjectId.get();
Затем нам просто нужно создать наш документ
и использовать сгенерированный идентификатор. Для этого мы можем предоставить его в конструкторе документа
:
Document document = new Document("_id", generatedId);
В качестве альтернативы мы можем использовать метод put()
:
document.put("_id", generatedId);
При использовании идентификатора, сгенерированного пользователем, мы должны с осторожностью генерировать новый ObjectId
перед каждой вставкой, поскольку дублирование идентификаторов запрещено. Повторяющиеся идентификаторы приведут к возникновению MongoWriteException
с повторяющимся ключевым сообщением.
Класс ObjectId
предоставляет несколько других конструкторов, которые позволяют нам устанавливать некоторые части идентификатора:
public ObjectId(final Date date)
public ObjectId(final Date date, final int counter)
public ObjectId(final int timestamp, final int counter)
public ObjectId(final String hexString)
public ObjectId(final byte[] bytes)
public ObjectId(final ByteBuffer buffer)
Но мы должны быть очень осторожны, когда используем эти конструкторы, поскольку уникальность идентификатора, предоставляемого драйверу, полностью зависит от нашего кода. Мы можем получить ошибку дублирования ключей в этих конкретных случаях:
- если мы используем одну и ту же дату (или метку времени) и счетчик несколько раз
- Если мы используем одну и ту же шестнадцатеричную
строку
, массивбайтов или
байтовый буфер
несколько раз
5. Вывод
В этой статье мы узнали, что такое уникальный идентификатор MongoDB для документов и как он работает. Затем мы увидели, как получить его как после вставки документа
в коллекцию
, так и даже до его вставки.
Как всегда, код этих примеров доступен на GitHub .