lmo
lmo

Reputation: 547

MongoDB Java: how to get write error document?

I'm inserting 1000 documents in mongodb 3.6 at once using an unordered bulk via mongodb java api 3.6.1 and the method insertMany(List<Document>).

try {
    collection.insertMany(docs);
} catch (MongoBulkWriteException e) {
    // e is :
   // Bulk write operation error on server myserver.com:27011. Write errors: [BulkWriteError{index=0, code=11000, message='E11000 duplicate key error collection: foodb.bar index: bar.id_1 dup key: { : 1 }', details={ }}].     
}

Let's say only one document triggered a duplicate key error. All others 999 documents were successfully inserted.
How can I know which document triggered the error ?

Of course when getting the duplicate key error, I could search my list of documents with the bar.id that was duplicated but it's inconvenient (it means parsing the WriteError message...) and if there is two documents with the same bar.id in the List<Document>, it's almost impossible to know which triggered the error without asking the db.

Thanks

Upvotes: 2

Views: 2290

Answers (1)

glytching
glytching

Reputation: 47895

MongoBulkWriteException contains a List<BulkWriteError>, each failed write will be represented by an element in this list. Each element in this list contains an index attribute which is populated with the index of the element in the supplied list of documents.

So, you can use this index to work out which of the supplied documents failed.

Here's a test case showing this in action:

@Test
public void canBulkWriteAndIdentifySpecificFailedDocuments() throws IOException {
    MongoClient mongoClient = new MongoClientFactory().create();

    MongoCollection<Document> collection = mongoClient.getDatabase("stackoverflow").getCollection("bulkwrite");

    // fresh start for this test case
    collection.drop();

    Document knownDocument = new Document().append("name", new BsonString("beep"));
    collection.insertOne(knownDocument);

    collection.createIndex(new BasicDBObject("name", 1), new IndexOptions().unique(true));

    int createDuplicateOnIndex = 2;
    List<Document> docs = Lists.newArrayList();
    for (int i = 0; i < 5; i++) {
        if (i == createDuplicateOnIndex) {
            // deliberately trigger a duplicate key exception
            docs.add(knownDocument);
        } else {
            docs.add(new Document().append("name", new BsonString("beep" + i)));
        }
    }

    try {
        collection.insertMany(docs, new InsertManyOptions().ordered(false));
    } catch (MongoBulkWriteException ex) {
        assertThat(ex.getWriteResult().getInsertedCount(), is(4));
        assertThat(ex.getMessage(), containsString("duplicate key error"));
        assertThat(ex.getWriteErrors().size(), is(1));
        assertThat(ex.getWriteErrors().get(0).getIndex(), is(createDuplicateOnIndex));
        assertThat(ex.getWriteErrors().get(0).getCode(), is(11000));
        assertThat(ex.getWriteErrors().get(0).getMessage(), startsWith("E11000 duplicate key error"));
    }
}

In this test case we ...

  1. Write a document
  2. Create a unique index on the target collection
  3. Write a collection of documents (using new InsertManyOptions().ordered(false) for an unordered write), one of which breaches the unique index
  4. Assert that the bulk insert causes a MongoBulkWriteException to be thrown and that this exception reports 4 successful writes and 1 failed write with E11000 duplicate key error and an index value which clearly shows that this failure is associated with the third document (index == 2) in the given list.

Upvotes: 3

Related Questions