1. Общ преглед
Понякога се нуждаем от идентификатора на документ, който току-що вмъкнахме в база данни на MongoDB. Например, може да искаме да изпратим обратно идентификатора като отговор на обаждащ се или да регистрираме създадения обект за отстраняване на грешки.
В този урок ще видим как идентификаторите се внедряват в MongoDB и как да извлечем идентификатора на документ, който току-що вмъкнахме в колекция чрез програма на Java.
2. Какъв е идентификационният номер на документ MongoDB?
Както във всяка система за съхранение на данни, MongoDB се нуждае от уникален идентификатор за всеки документ, съхраняван в колекция. Този идентификатор е еквивалентен на първичния ключ в релационни бази данни.
В MongoDB този идентификатор се състои от 12 байта:
- 4-байтова стойност на времеви печат представлява секундите от епохата на Unix
- 5-байтова произволна стойност, генерирана веднъж на процес. Тази произволна стойност е уникална за машината и процеса.
- 3-байтов нарастващ брояч
Идентификационният номер се съхранява в поле с име _id и се генерира от клиента Това означава, че идентификаторът трябва да бъде генериран преди изпращане на документа в базата данни. От страна на клиента можем да използваме идентификатор, генериран от драйвер, или да генерираме персонализиран идентификатор.
Можем да видим, че документите, създадени от един и същ клиент в една и съща секунда, ще имат първите 9 общи байта. Следователно уникалността на идентификатора разчита на брояча в този случай. Броячът позволява на клиента да създаде над 16 милиона документа за една и съща секунда.
Въпреки че започва с времева марка, трябва да внимаваме идентификаторът да не се използва като критерий за сортиране. Това е така, защото документите, създадени в една и съща секунда, не е гарантирано, че ще бъдат сортирани по дата на създаване, тъй като броячът не е гарантиран, че ще бъде монотонен. Освен това различните клиенти може да имат различни системни часовници.
Драйверът на Java използва генератор на произволни числа за брояча, който не е монотонен. Ето защо не трябва да използваме генерирания от драйвера ID за сортиране по дата на създаване.
3. ObjectId Клас
Уникалният идентификатор се съхранява в ObjectId клас, който предоставя удобни методи за получаване на данните, съхранявани в идентификатора, без да ги анализирате ръчно.
Например, ето как можем да получим датата на създаване на идентификатора:
Date creationDate = objectId.getDate();
По същия начин можем да извлечем времевата марка на идентификатора за секунди :
int timestamp = objectId.getTimestamp();
ObjectId class също така предоставя методи за получаване на брояча, идентификатора на машината или идентификатора на процеса, но всички те са отхвърлени.
4. Извличане на ID
Основното нещо, което трябва да запомните е, че в MongoDB клиентът генерира уникалния идентификатор на Документ преди да го изпратите в клъстера. Това е в контраст с последователностите в релационни бази данни. Това прави извличането на този идентификатор доста лесно.
4.1. Генериран от драйвер ID
Стандартният и лесен начин за генериране на уникалния идентификатор на документ е като оставите шофьора да свърши работата. Когато вмъкнем нов Документ към колекция , ако няма _id полето съществува в Документа , драйверът генерира нов ObjectId преди да изпратите командата за вмъкване към клъстера.
Нашият код за вмъкване на нов Документ във вашата колекция може да изглежда така:
Document document = new Document();
document.put("name", "Shubham");
document.put("company", "Baeldung");
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 class предоставя няколко други конструктора, които ни позволяват да зададем някои части от идентификатора:
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)
Но трябва да бъдем много внимателни, когато използваме тези конструктори, тъй като уникалността на идентификатора, предоставена на драйвера, разчита изцяло на нашия код. Можем да получим грешка при дублирани ключове в тези конкретни случаи:
- ако използваме няколко пъти една и съща дата (или времева марка) и брояч
- Ако използваме същия шестнадесетичен String , байт масив или ByteBuffer няколко пъти