Get Last Inserted Document ID in MongoDB With Java Driver – 用Java驱动获取MongoDB中最后插入的文档ID

最后修改: 2022年 1月 29日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Sometimes, we need the ID of a document we just inserted into a MongoDB database. For instance, we may want to send back the ID as a response to a caller or log the created object for debugging.

有时,我们需要知道刚刚插入MongoDB数据库中的文档的 ID。例如,我们可能希望将 ID 作为响应发回给调用者,或者记录所创建的对象以进行调试。

In this tutorial, we’ll see how IDs are implemented in MongoDB and how to retrieve the ID of a document we just inserted in a collection via a Java program.

在本教程中,我们将看到ID是如何在MongoDB中实现的,以及如何通过一个Java程序检索我们刚刚插入到一个集合中的文档的ID。

2. What Is the ID of a MongoDB Document?

2.什么是MongoDB文档的ID?

As in every data storage system, MongoDB needs a unique identifier for each document stored in a collection. This identifier is equivalent to the primary key in relational databases.

正如每个数据存储系统一样,MongoDB需要为存储在集合中的每个文档提供一个唯一的标识符。这个标识符相当于关系型数据库中的主键。

In MongoDB, this ID is composed of 12 bytes:

在MongoDB中,这个ID是由12个字节组成的。

  • a 4-byte timestamp value represents the seconds since the Unix epoch
  • a 5-byte random value generated once per process. This random value is unique to the machine and the process.
  • a 3-byte incrementing counter

The ID is stored in a field named _id and is generated by the client. This means that the ID must be generated before sending the document to the database. On the client side, we can either use a driver-generated ID or generate a custom ID.

ID存储在一个名为_id的字段中,由客户端生成。这意味着在将文档发送到数据库之前必须生成ID。在客户端,我们可以使用驱动程序生成的ID,或者生成一个自定义的ID。

We can see that documents created by the same client in the same second will have the first 9 bytes in common. Therefore, the uniqueness of the ID relies on the counter in this case. The counter lets a client create over 16 million documents in the same second.

我们可以看到,同一客户在同一秒内创建的文件将有前9个字节的共同点。因此,在这种情况下,ID的唯一性依赖于计数器。计数器让客户端在同一秒内创建超过1600万个文件。

Although it starts with a timestamp, we should be careful that the identifier is not used as a sorting criterion. This is because documents created in the same second are not guaranteed to be sorted by creation date, as the counter is not guaranteed to be monotonic. Also, different clients may have different system clocks.

虽然它是以时间戳开始的,但我们应该注意不要把标识符作为排序的标准。这是因为在同一秒内创建的文件不能保证按创建日期排序,因为计数器不能保证是单调的。另外,不同的客户可能有不同的系统时钟。

The Java driver uses a random number generator for the counter, which is not monotonic. That’s why we should not use the driver-generated ID for sorting by creation date.

Java驱动使用了一个随机数生成器作为计数器,它不是单调的。这就是为什么我们不应该使用驱动生成的ID来按创建日期排序。

3. The ObjectId Class

3.ObjectId

The unique identifier is stored in an ObjectId class which provides convenient methods to get the data stored in the ID without parsing it manually.

唯一的标识符被存储在一个ObjectId类中,该类提供了方便的方法来获取存储在ID中的数据,而无需手动解析。

For example, here’s how we can get the creation date of the ID:

例如,我们可以通过以下方式获得ID的创建日期。

Date creationDate = objectId.getDate();

Likewise, we can retrieve the timestamp of the ID in seconds :

同样地,我们可以检索ID的时间戳,单位是秒。

int timestamp = objectId.getTimestamp();

The ObjectId class also provides methods to get the counter, the machine identifier, or the process identifier, but they’re all deprecated.

ObjectId类还提供了获取计数器、机器标识符或进程标识符的方法,但它们都已被废弃。

4. Retrieving the ID

4.检索ID

The main thing to remember is that, in MongoDB, the client generates the unique identifier of a Document before sending it to the cluster. This is in contrast to sequences in relational databases. This makes the retrieval of this ID quite easy.

需要记住的主要一点是,在MongoDB中,客户端在将一个Document发送到集群之前,会生成其唯一的标识符。这与关系型数据库中的序列相反。这使得该ID的检索相当容易。

4.1. Driver-generated ID

4.1.驱动程序生成的ID

The standard and easy way to generate the unique ID of a Document is by letting the driver do the job. When we insert a new Document to a Collection, if no _id field exists in the Document, the driver generates a new ObjectId before sending the insert command to the cluster.

生成Document的唯一ID的标准而简单的方法是让驱动程序来完成这项工作。当我们向Collection插入一个新的Document时,如果Document中不存在_id字段,驱动程序在向集群发送插入命令之前生成一个新的ObjectId

Our code to insert a new Document into your Collection may look like this :

我们插入一个新的Document到你的Collection的代码可能看起来像这样。

Document document = new Document();
document.put("name", "Shubham");
document.put("company", "Baeldung");
collection.insertOne(document);

We can see that we never indicate how the ID must be generated.

我们可以看到,我们从未指出必须如何生成ID。

When the insertOne() method returns, we can get the generated ObjectId from the Document :

insertOne()方法返回时,我们可以从Document获得生成的ObjectId

ObjectId objectId = document.getObjectId("_id");

We can also retrieve the ObjectId like a standard field of the Document and then cast it to ObjectId:

我们也可以像Document的一个标准字段一样检索ObjectId,然后把它投给ObjectId

ObjectId oId = (ObjectId) document.get("_id");

4.2. Custom ID

4.2.自定义ID

The other way to retrieve the ID is to generate it in our code and put it in the Document like any other field. If we send a Document with an _id field to the driver, it will not generate a new one.

检索ID的另一种方法是在我们的代码中生成它,并像其他字段一样把它放在Document中。如果我们把带有_id字段的Document发送给驱动程序,它将不会生成一个新的ID。

We might require this in some cases where we need the ID of the MongoDB Document before inserting the Document in the Collection.

在某些情况下,我们可能需要这样做,即在将Document插入Collection中之前需要MongoDBDocument的ID。

We can generate a new ObjectId by creating a new instance of the class :

我们可以通过创建一个新的类的实例来生成一个新的ObjectId

ObjectId generatedId = new ObjectId();

Or, we can also invoke the static get() method of the ObjectId class:

或者,我们也可以调用ObjectId类的静态get()方法。

ObjectId generatedId = ObjectId.get();

Then, we just have to create our Document and use the generated ID. To do so, we can provide it in the Document constructor:

然后,我们只需要创建我们的Document并使用生成的ID。要做到这一点,我们可以在Document构造函数中提供它。

Document document = new Document("_id", generatedId);

Alternatively, we can use the put() method:

另外,我们可以使用put()方法。

document.put("_id", generatedId);

When using a user-generated ID, we must be cautious to generate a new ObjectId before each insertion, as duplicated IDs are forbidden. Duplicate IDs will result in a MongoWriteException with a duplicate key message.

当使用用户生成的ID时,我们必须谨慎地在每次插入前生成一个新的ObjectId,因为重复的ID是禁止的。重复的ID将导致MongoWriteException和重复的键信息。

The ObjectId class provides several other constructors which allow us to set some parts of the identifier:

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)

But, we should be very careful when we use those constructors as the uniqueness of the ID provided to the driver relies entirely on our code. We can get duplicate keys error in these particular cases:

但是,当我们使用这些构造函数时,我们应该非常小心,因为提供给驱动的ID的唯一性完全依赖于我们的代码。在这些特殊情况下,我们可能会得到重复键的错误。

  • if we use the same date (or timestamp) & counter combo several times
  • If we use the same hexadecimal String, byte array, or ByteBuffer several times

5. Conclusion

5.总结

In this article, we learned what the MongoDB unique identifier for documents is and how it works. Then, we saw how to retrieve it both after inserting a Document in a Collection and even before inserting it.

在这篇文章中,我们了解了MongoDB的唯一标识符是什么,以及它是如何工作的。然后,我们看到了如何在Document插入Collection之后以及甚至在插入之前检索它。

As always, the code for these examples is available over on GitHub.

一如既往,这些示例的代码可在GitHub上获得