title: Mongodb upsert operation seems not atomic which throws DuplicateKeyException
body: <p>I have a mongodb database named 'msgdb', and a collection named 'roster'. The document in 'roster' is like below:</p>
  
  <pre><code>{
    "userId": "sn99933289",
    "rosterGroups": [
      {
        "groupId": "242326",
        "groupName": "buddy",
        "rosterItems": [
  
        ]
      }
    ],
    "version": NumberInt(1)
  }
  </code></pre>
  
  <p>I set the field '_id' as the shard key like below:</p>
  
  <p>db.runCommand({ shardcollection: "msgdb.roster", key:{ _id:"hashed" }})</p>
  
  <p>The Java code which calls the upsert method:</p>
  
  <pre><code>import com.mongodb.BasicDBObject;
  import org.springframework.data.mongodb.core.MongoTemplate;
  import org.springframework.data.mongodb.core.query.Criteria;
  import org.springframework.data.mongodb.core.query.Query;
  import org.springframework.data.mongodb.core.query.Update;
  
      private void saveRoster(Roster roster) {
          BasicDBObject dbObject = new BasicDBObject();
          mongoTemplate.getConverter().write(roster, dbObject);
          dbObject.remove("version");
          dbObject.remove("_class");
          Update update = new Update();
          for (Map.Entry&lt;String, Object&gt; entry : dbObject.entrySet()) {
              update.set(entry.getKey(), entry.getValue());
          }
          update.inc("version", 1);
          Criteria criteria = Criteria.where("_id").is(roster.getUserId());
          Query query = new Query(criteria);
          mongoTemplate.upsert(query, update, "roster");
      }
  </code></pre>
  
  <p>I found the DuplicateKeyException from the application log. It seems the upsert operation is not atomic. More specific exception stack trace is as below. How to avoid this exception? Any help/hint is appreciated.</p>
  
  <pre><code>org.springframework.dao.DuplicateKeyException: Write failed with error code 11000 and error message 'E11000 duplicate key error collection: msgdb.roster index: _id_ dup key: { : "sn88332138" }'; nested exception is com.mongodb.DuplicateKeyException: Write failed with error code 11000 and error message 'E11000 duplicate key error collection: msgdb.roster index: _id_ dup key: { : "sn88332138" }'
  at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:69) ~[spring-data-mongodb-1.7.1.RELEASE.jar:na]
  at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java:2011) ~[spring-data-mongodb-1.7.1.RELEASE.jar:na]
  at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:463) ~[spring-data-mongodb-1.7.1.RELEASE.jar:na]
  at org.springframework.data.mongodb.core.MongoTemplate.doUpdate(MongoTemplate.java:1086) ~[spring-data-mongodb-1.7.1.RELEASE.jar:na]
  at org.springframework.data.mongodb.core.MongoTemplate.upsert(MongoTemplate.java:1052) ~[spring-data-mongodb-1.7.1.RELEASE.jar:na]
  at com.suning.im.server.center.roster.RosterServiceImpl.saveRoster(RosterServiceImpl.java:235) ~[classes:na]
  at com.suning.im.server.center.roster.RosterServiceImpl.getRoster(RosterServiceImpl.java:68) ~[classes:na]
  at com.suning.im.server.center.roster.RosterServiceImpl.getRosterPresencesWithVirtual(RosterServiceImpl.java:251) ~[classes:na]
  at sun.reflect.GeneratedMethodAccessor54.invoke(Unknown Source) ~[na:na]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_25]
  at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_25]
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) ~[na:1.7.0_25]
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) ~[na:1.7.0_25]
  at java.lang.Thread.run(Thread.java:724) ~[na:1.7.0_25]
  </code></pre>