Spring mongorepository save throws duplicate key exception
Asked Answered
F

5

9

I am using the java and Spring. As a test, I query an object by id, then try to save the same object without updating anything. I get a duplicate key exception when I do this. According to what I've read, MongoRepository.save() should do an insert if the _id is null and an update otherwise. Clearly, I should get an update.

A bit of code:

// Succeeds
Datatype sut = mongoRepository.findOne("569eac0dd4c623dc65508679");  

// Fails with duplicate key.
mongoRepository.save(sut);  

Why? Repeat the above with object of other classes and they work. How can I trouble shoot this? I don't see how to break it down and isolate the problem.

Thanks

The error:

27906 [http-bio-8080-exec-3] 2016-05-02 13:00:26,304 DEBUG org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver -

Resolving exception from handler 
[
  public gov.nist.healthcare.tools.hl7.v2.igamt.lite.web.DatatypeSaveResponse 
gov.nist.healthcare.tools.hl7.v2.igamt.lite.web.controller.DatatypeController.save(
  gov.nist.healthcare.tools.hl7.v2.igamt.lite.domain.Datatype) 
throws gov.nist.healthcare.tools.hl7.v2.igamt.lite.web.exception.DatatypeSaveException
]:
org.springframework.dao.DuplicateKeyException: {
   "serverUsed" : "127.0.0.1:27017" ,
   "ok" : 1 ,
   "n" : 0 , 
   "err" : "E11000 duplicate key error index: igl.datatype.$_id_ dup key: { : ObjectId('569eac0dd4c623dc65508679') }" ,
   "code" : 11000};
nested exception is com.mongodb.MongoException$DuplicateKey: {
  "serverUsed" : "127.0.0.1:27017" ,
  "ok" : 1 ,
  "n" : 0 ,
  "err" : "E11000 duplicate key error index: igl.datatype.$_id_ dup key: { : ObjectId('569eac0dd4c623dc65508679') }" ,
  "code" : 11000}

...repeats

I just made a discovery. When saving as shown above, spring attempts an insert, this even though _id is populated.

When saving other objects ( not shown, but similar), spring performs, an update, and yes _id is again populated.

Why the difference? The documentation says spring should update when _id is populated and insert when it is not.

Is there anything else that can be causing this? Something in my object? perhaps my read converter?

Update: I just met with the team. Upon scrutiny we determined we no longer need read converters. Problem solved by another means.

Fabien answered 3/5, 2016 at 0:0 Comment(1)
How did you solve the problem ?Butanol
A
8

In my case the issue was that I added the version for my data model class.

@Version
private Long version;

The old documents did not have one, it resolved to null, and MongoTemplate decided that this is a new document.

In this case just initialize the version with the default value (private Long version = 0;).

Argybargy answered 16/8, 2021 at 14:49 Comment(3)
For me it was similar. I have a entity with @Id and @Version. I forgot to set the version field when updating. So I got the DuplicateKeyException. When I also set the version field for the update, it worked.Gitlow
@Gitlow So you need to manually increment the version yourself during the update? I thought it should be automatic?Egypt
@Egypt no, it 100% should be automaticArgybargy
P
2

When using read converters or write converters you can solve the issue by ensuring the object to be saved contains a non-null id field.

The SimpleMongoRepository checks if the entity is new before performing a conversion. In our instance, we had an object that did not have an id field and the write converter would add it.

Adding a populated id field to the object informs the SimpleMongoRepository to call save instead of insert.

The decision happens here. Your code may vary by Spring version. I hope this helps.

@Override
public <S extends T> S save(S entity) {

    Assert.notNull(entity, "Entity must not be null!");

    if (entityInformation.isNew(entity)) {
        return mongoOperations.insert(entity, entityInformation.getCollectionName());
    }

    return mongoOperations.save(entity, entityInformation.getCollectionName());
}
Photocopy answered 26/1, 2020 at 21:47 Comment(0)
C
0

In the database side, You may have created Unique indexes. please look at "https://docs.mongodb.com/manual/core/index-unique/" for more information.

Coacher answered 16/11, 2018 at 7:11 Comment(0)
C
0

Implement equals and hashcode methods in your Datatype entity, and make sure that mongoRepository extends CrudRepositor (as it is described in https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#repositories) to ensure that if the objects are equals save method should merge them instead of save a new one.

Considered answered 16/11, 2018 at 7:49 Comment(0)
W
0

I had a similar experience, save() was throwing DuplicateKeyException even though I just modified some fields and called save on the modified version. In my case the problem was that my @Id field was long instead of Long.

Wyant answered 13/1, 2024 at 20:36 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.