Search code examples
javamongodbmongodb-java

How do I get array _ids of documents failed to insert/delete/update in bulk operation?


In case of bulkWrite(), I want array of _ids of successfully processed documents OR failed documents, along with reason for failure.

Following is the attempt I made. Suggest more easy approach if possible.

try {
    collection.insertMany(documents, new InsertManyOptions().ordered(false));
} catch (DuplicateKeyException dke) {
    LOGGER.error("{}", dke);
} catch (MongoBulkWriteException mbwe) {
    List<BulkWriteError> errors = mbwe.getWriteErrors();
    for (BulkWriteError error : errors) {
        LOGGER.error("{}", error.getMessage());
    }
} catch (Exception ex) {
    LOGGER.error("{}", ex.getCause());
}

When I insert document with duplicate _ids, I supposed to get DuplicateKeyException as per javadoc, but I am getting MongoBulkWriteException.

I am using java 8 and mongodb 3.2.1 drivers


Solution

  • insertMany throws only the following exceptions:

    • MongoBulkWriteException - if there's an exception in the bulk write operation

    • MongoException - if the write failed due some other failure

    However the exception carries the cause of it and in the case of a duplicated id will be something like:

    insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.restaurants.$_id_  dup key: { : ObjectId('56c8ac3146235e4898bb696c') }
    

    So since you have the information in the message you can extract with a regular expression the ids of the documents that failed in an array.

    The code would be something like that (I am giving it inline in your code):

            List<String>duplicateIds = new ArrayList<String>();
            List<BulkWriteError> errors = mbwe.getWriteErrors();
            for (BulkWriteError error : errors) {
    
                LOGGER.error("{}", error.getMessage());
    
                // extract from error.message the id of the duplicated document, (11000 is the duplicate id code)
                if (error.getCode() == 11000) {
                    Matcher m = Pattern.compile("[0-9a-f]{24}")
                            .matcher(error.getMessage());
                    m.find();
                    duplicateIds.add(m.group());
                }
    
            }
            // here the duplicateIds will hold all the found ids, you can print them in console for example:
            System.out.println(duplicateIds.toString());
            // and do whatever else you like with them
    

    The above code will catch the duplicated Ids - if you want to make it to catch other errors it is easy to adapt it accordingly.

    UPDATE:

    If you want to use bulkWrite() you can use exactly the same code since it throws the same exceptions (MongoBulkWrite, MongoException) as insertMany(), see BulkWrite()

    If you want to update the code to catch other exceptions it is easily expandable:

    1. see what the specific message and error code is for the exception you want to catch from the logs.
    2. add an if block as the one I gave for that particular error code to extract the ids with a regular expression and add them to the array you have initialized for that kind of error
    3. do your handling in the end