MongoDB 4.4,Java 驱动程序 4.2.3 - InsertManyResult.getInsertedIds() 不返回所有插入文档的 ID

MongoDB 4.4, Java driver 4.2.3 - InsertManyResult.getInsertedIds() not returning IDs for all inserted documents

我试图在 InsertMany 操作成功后为插入的文档检索 _id 的值。为此,我使用 InsertManyResult.getInsertedIds()。虽然这种方法在大多数情况下都有效,但在某些情况下,并非所有 _id 值都被检索到。

我不确定我是否做错了什么,但我会假设 InsertManyResult.getInsertedIds() returns _id 对于 all 插入的文件。

问题详情

我在 MongoDB 中插入 1000 个文档,分两批 500 个文档。每个文档的大小约为 1 MB。

使用 InsertMany 插入批次后,我尝试通过 InsertManyResult.getInsertedIds() 读取 _id 的值并将其保存到集合中以备后用。

我假设通过 InsertMany 插入 500 文档后 InsertManyResult.getInsertedIds() 会 return 500 _id 值。然而,returning 仅 16 _id 个值 500.

当我直接通过 Mongo Shell 检查 Mongo 集合时,我看到所有记录都已成功插入。我的测试集中有 1000 个文档。我只是无法通过 InsertManyResult.getInsertedIds() 获取所有插入文档的 _id。对于插入的 1000 个文档,我只得到 32 _id

JSON结构

为了重现这个问题,我有 一个 JSON,大小约为 1 MB,如下所示。

{
  "textVal" : "RmKHtEMMzJDXgEApmWeoZGRdZJZerIj1",
  "intVal" : 161390623,
  "longVal" : "98213019054010317",
  "timestampVal" : "2020-12-31 23:59:59.999",
  "numericVal" : -401277306,
  "largeArrayVal" : [ "MMzJDXg", "ApmWeoZGRdZJZerI", "1LhTxQ", "adprPSb1ZT", ..., "QNLkBZuXenmYE77"]

}

请注意,键 largeArrayVal 几乎包含所有数据。为了便于阅读,我省略了大部分值。

示例代码

下面的代码将上面显示的 JSON 解析为 Document,然后通过 InsertMany 插入到 MongoDB。完成后,我尝试使用 InsertManyResult.getInsertedIds().

插入 _id
private static final int MAX_DOCUMENTS = 1000;
private static final int BULK_SIZE = 500;

private static List<ObjectId> insertBatchReturnIds(List<Document> insertBatch)
{
  List<ObjectId> insertedIds = new ArrayList<ObjectId>();
  InsertManyResult insertManyResult;

  insertManyResult = mongoClient.getDatabase(MONGO_DATABASE).getCollection(MONGO_COLLECTION).insertMany(insertBatch);
  insertManyResult.getInsertedIds().forEach((k,v) -> insertedIds.add(v.asObjectId().getValue()));

  System.out.println("Batch inseted:");
  System.out.println(" - Was acknowladged: " + Boolean.toString(insertManyResult.wasAcknowledged()).toUpperCase());
  System.out.println(" - InsertManyResult.getInsertedIds().size(): " + insertManyResult.getInsertedIds().size());

  return insertedIds;
}

private static void insertDocuments()
{
  int documentsInserted = 0;
  List<Document> insertBatch = new ArrayList<Document>();
  List<ObjectId> insertedIds = new ArrayList<ObjectId>();
  final String largeJson = loadLargeJsonFromFile("d:\test-sample.json");

  System.out.println("Starting INSERT test...");
  while (documentsInserted < MAX_DOCUMENTS)
  {
    insertBatch.add(Document.parse(largeJson));
    documentsInserted++;

    if (documentsInserted % BULK_SIZE == 0)
    {
     insertedIds.addAll(insertBatchReturnIds(insertBatch));
     insertBatch.clear();
    }
  }
  if (insertBatch.size() > 0)
    insertedIds.addAll(insertBatchReturnIds(insertBatch));
  System.out.println("INSERT test finished");

  System.out.println(String.format("Expected IDs retrieved: %d. Actual IDs retrieved: %d.", MAX_DOCUMENTS, insertedIds.size()));
  if (insertedIds.size() != MAX_DOCUMENTS)
    throw new IllegalStateException("Not all _ID were returned for each document in batch");
}

示例输出

Starting INSERT test...
Batch inseted:
 - Was acknowladged: TRUE
 - InsertManyResult.getInsertedIds().size(): 16
Batch inseted:
 - Was acknowladged: TRUE
 - InsertManyResult.getInsertedIds().size(): 16
INSERT test finished
Expected IDs retrieved: 1000. Actual IDs retrieved: 32.
Exception in thread "main" java.lang.IllegalStateException: Not all _ID were returned for each document in batch

我的问题

  1. InsertManyResult.getInsertedIds() 是否意味着 return _id 插入 所有 文档?
  2. 我使用的方法 InsertManyResult.getInsertedIds() 正确吗?
  3. 插入的大小 JSON 会是这里的一个因素吗?
  4. 我应该如何使用 InsertManyResult 来获取插入文档的 _id

备注

我知道我可以在 Document.parse 之后读取 _id,因为它是生成此文件的驱动程序,或者我可以在插入文档后 select _id
我想知道如何使用 InsertManyResult.getInsertedIds() 来实现这一点,因为它似乎适合这个目的。

您的文档有 1 MB 大,因此一个命令最多只能包含 16 个文档。 driver 确实会自动将整套文档分成几批,但您似乎一次从一批中读取 ID,因此问题可能是以下之一:

  • 存在一个 driver 问题,即它在将结果返回到您的应用程序之前不会将批处理结果合并在一起
  • driver 一次给你一批结果,因此你确实得到了所有的 id,但不是你期望的部分(在这种情况下没有错误,但你确实需要使用 driver)
  • 提供的批处理

Ruby 中的以下测试按预期工作,生成 100 个 ID:

c = Mongo::Client.new(['localhost:14920'])

docs = [{a: 'x'*1_000_000}]*100
res = c['foo'].insert_many(docs)

p res.inserted_ids.length
pp res.inserted_ids

这是 Java 驱动程序中的错误,正在 https://jira.mongodb.org/browse/JAVA-4436 中进行跟踪(2022 年 1 月 5 日报告)。