1. 概述

有时我们需要获取刚插入MongoDB数据库的文档ID。比如想将ID作为响应返回给调用者,或记录创建对象用于调试。

本教程将详解MongoDB ID的实现机制,以及如何通过Java程序获取刚插入集合的文档ID。

2. MongoDB文档ID解析

与所有存储系统一样,MongoDB需要为集合中每个文档分配唯一标识符,相当于关系数据库的主键。

MongoDB的ID由12字节组成:

  • 4字节时间戳:表示Unix纪元以来的秒数
  • 5字节随机值:每个进程生成一次,确保机器和进程唯一性
  • 3字节递增计数器

关键点:ID存储在_id字段中,由客户端生成。这意味着必须在发送文档到数据库前创建ID。客户端可选择使用驱动生成的ID或自定义ID。

注意:同一客户端同一秒内创建的文档会共享前9字节,此时ID唯一性依赖计数器(允许单秒创建超1600万文档)。

⚠️ 踩坑提醒:ID虽含时间戳,但切勿用作排序依据,原因有三:

  1. 同秒创建的文档无法保证按创建日期排序
  2. 计数器不保证单调递增
  3. 不同客户端可能存在时钟差异

Java驱动对计数器使用随机数生成器(非单调),故绝不能用驱动生成的ID按创建日期排序。

3. ObjectId类详解

唯一标识符存储在ObjectId类中,提供便捷方法解析ID数据而无需手动处理。

获取ID创建日期:

Date creationDate = objectId.getDate();

获取秒级时间戳:

int timestamp = objectId.getTimestamp();

注:ObjectId类提供的计数器、机器标识符等方法已弃用。

4. ID获取方案

核心原则:MongoDB中客户端在发送文档到集群前生成唯一ID(区别于关系数据库序列),这使得ID获取变得简单。

4.1 驱动自动生成ID

标准做法:让驱动自动生成ID。插入新文档时,若_id字段不存在,驱动会在发送插入命令前自动创建ObjectId

插入示例:

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

获取驱动生成的ID(两种方式):

// 方式1:直接获取
ObjectId objectId = document.getObjectId("_id");

// 方式2:标准字段获取+强转
ObjectId oId = (ObjectId) document.get("_id");

4.2 自定义ID方案

替代方案:代码中生成ID并放入文档。若文档包含_id字段,驱动将不会生成新ID。

适用场景:需要在文档插入集合前获取其ID(如关联操作)。

生成自定义ID(两种方式):

// 方式1:构造函数生成
ObjectId generatedId = new ObjectId();

// 方式2:静态方法生成
ObjectId generatedId = ObjectId.get();

将ID注入文档(两种方式):

// 方式1:构造函数注入
Document document = new Document("_id", generatedId);

// 方式2:put方法注入
document.put("_id", generatedId);

⚠️ 严正警告:使用自定义ID时必须**每次插入前生成新ObjectId**,重复ID会触发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)

踩坑预警:使用这些构造函数需格外谨慎,ID唯一性完全依赖你的代码!以下情况会导致重复键错误:

  • 重复使用相同日期/时间戳+计数器组合
  • 重复使用相同十六进制字符串/字节数组/ByteBuffer

5. 总结

本文深入解析了MongoDB文档唯一标识符的机制及实现,并提供了两种ID获取方案:

  1. 驱动自动生成:最简单推荐方案
  2. 自定义ID:适用于需要预生成ID的场景

示例代码已上传至GitHub仓库,欢迎参考实践。


原始标题:Get Last Inserted Document ID in MongoDB With Java Driver | Baeldung