javamongodbscalamongodb-javacasbah

How to upsert document in MongoDB Java driver 3


what is the idiomatic way to upsert a document using version 3 of the mongodb java driver (specifically v3.0.1)?

We have a collection for sessions and when a new session gets created or modified, we want to upsert it in one operation - rather than having to query if a document exists yet and then either inserting or replacing.

Our old upsertion code used the scala driver casbah 2.7.3. It looked like:

import com.mongodb.casbah.MongoCollection
import com.mongdb.DBObject
val sessionCollection: MongoCollection = ...
val sessionKey: String = ...
val sessionDocument: DBObject = ... // Either create a new one, or find and modify an existing one

sessionCollection.update(
    "_id" -> sessionKey,
    sessionDocument
    upsert = true
)

In our current project we're just using the plain java 3.0.1 driver and we're using BsonDocument instead of DBObject to make it more typsafe. I tried to replace the above with something like:

import com.mongodb.client.MongoCollection
val sessionCollection: MongoCollection = ...
val sessionKey: String = ...
val sessionDocument: BsonDocument = // Either create a new one, or find and modify an existing one

val updateOptions = new UpdateOptions
updateOptions.upsert(true)

sessionCollection.updateOne(
    "_id" -> new BsonString(sessionKey),
    sessionDocument,
    updateOptions
)

This throws the error "java.lang.IllegalArgumentException: Invalid BSON field name ...". The error is covered in this question but the op in that question wasn't trying to upsert in one operation - they were using context to decide whether to replace/update/insert etc...

I'm happy with code samples in scala or java.

Thanks!


Solution

  • In the Mongo Java Driver 3.0 series we added a new Crud API which is more explicit and therefore beginner friendly. This initiative has been rolled out over a number of MongoDB Drivers but it does contain some changes compared to the older API.

    As you are not updating an existing document using an update operator, the updateOne method is not appropriate.

    The operation you describe is a replaceOne operation and can be run like so:

    sessionCollection.replaceOne(
        "_id" -> new BsonString(sessionKey),
        sessionDocument,
        (new UpdateOptions()).upsert(true)
    )