NoSQL Top

Build a Dashboard Using Cassandra, Astra, and Stargate:

>> CHECK OUT THE ARTICLE
Persistence top

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

>> CHECK OUT THE COURSE

1. Overview

Upsert is a combination of insert and update (inSERT + UPdate = upsert). We can use the upsert with different update methods, i.e., update, findAndModify, and replaceOne.

Here in MongoDB, the upsert option is a Boolean value. Suppose the value is true and the documents match the specified query filter. In that case, the applied update operation will update the documents. If the value is true and no documents match the condition, this option inserts a new document into the collection. The new document will contain the fields based on filter and applied operations.

In this tutorial, we'll first look at the upsert in MongoDB Shell query and then use the Java driver code.

2. Database Initialization

Before we move forward to perform the upsert operations, first we need to set up a new database baeldung and a sample collection, vehicle:

db.vehicle.insertMany([
{
    "companyName":"Nissan", 
    "modelName":"GTR",
    "launchYear":2016,
    "type":"Sports",
    "registeredNo":"EPS 5561"
},
{ 
    "companyName":"BMW",
    "modelName":"X5",
    "launchYear":2020,
    "type":"SUV",
    "registeredNo":"LLS 6899"
},
{
    "companyName":"Honda",
    "modelName":"Gold Wing",
    "launchYear":2018,
    "type":"Bike",
    "registeredNo":"LKS 2477"
}]);

In case of successful insertion, the above command will print a JSON similar to the one shown below:

{
    "acknowledged" : true, 
    "insertedIds" : [
        ObjectId("623c1db39d55d4e137e4781b"),
	ObjectId("623c1db39d55d4e137e4781c"),
	ObjectId("623c1db39d55d4e137e4781d")
    ]
}

We have successfully added the dummy data into the collection vehicle.

3. Using the update Method

In this section, we'll learn to use the upsert option with the update method. The main purpose of the upsert option is to update the existing document based on the applied filter or insert a new document if the filter doesn't get the match.

As an illustration, we will use the $setOnInsert operator with the upsert option to get an additional advantage on inserting new fields into the document.

Let's check out a query in which the filter condition matches the existing document of the collection:

db.vehicle.update(
{
    "modelName":"X5"
},
{
    "$set":{
        "companyName":"Hero Honda"
    }
},
{
    "upsert":true
});

The above query will return the following document:

{ 
    "nMatched" : 1, 
    "nUpserted" : 0,
    "nModified" : 1 
}

Here, we'll see the Java driver code corresponding to the above mongo shell query:

UpdateOptions options = new UpdateOptions().upsert(true);
UpdateResult updateResult = collection.updateOne(Filters.eq("modelName", "X5"), 
  Updates.combine(Updates.set("companyName", "Hero Honda")), options);
System.out.println("updateResult:- " + updateResult);

In the above query, the field modelName “X5” already exists in the collection, so the field companyName of that document will be updated to “Hero Honda”.

Now let's check out an example of upsert option using the $setOnInsert operator. It will be applicable only in the case of adding a new document:

db.vehicle.update(
{
    "modelName":"GTPR"
},
{
    "$set":{
        "companyName":"Hero Honda"
    },
    "$setOnInsert":{
        "launchYear" : 2022,
	"type" : "Bike",
	"registeredNo" : "EPS 5562"
    },  
},
{
    "upsert":true
});

The above query will return the following document:

{
    "nMatched" : 0,
    "nUpserted" : 1,
    "nModified" : 0,
    "_id" : ObjectId("623b378ed648af670fe50e7f")
}

The Java driver code of the above update query with the $setOnInsert option will be:

UpdateResult updateSetOnInsertResult = collection.updateOne(Filters.eq("modelName", "GTPR"),
  Updates.combine(Updates.set("companyName", "Hero Honda"),
  Updates.setOnInsert("launchYear", 2022),
  Updates.setOnInsert("type", "Bike"),
  Updates.setOnInsert("registeredNo", "EPS 5562")), options);
System.out.println("updateSetOnInsertResult:- " + updateSetOnInsertResult);

Here, in the above query, the filter condition of field modelName “GTPR” doesn't match any collection document, so we'll add a new document to the collection. The key point to note is that the $setOnInsert adds all the fields into the new document.

4. Using the findAndModify Method

We can also use the upsert option using the findAndModify method. For this method, the default value of the upsert option is false. If we set the upsert option to true, it'll perform precisely the same as the update method.

Let's check out a use case of the findAndModify method with the upsert option true:

db.vehicle.findAndModify(
{
    query:{
        "modelName":"X7"
    },
    update: {
        "$set":{
            "companyName":"Hero Honda"
        }
    },
    "upsert":true,
    "new":true
});

In this case, the above query will return the newly created document. Let's check out the Java driver code of the above query:

FindOneAndUpdateOptions upsertOptions = new FindOneAndUpdateOptions();
  upsertOptions.returnDocument(ReturnDocument.AFTER);
  upsertOptions.upsert(true);
Document resultDocument = collection.findOneAndUpdate(Filters.eq("modelName", "X7"),
  Updates.set("companyName", "Hero Honda"), upsertOptions);
System.out.println("resultDocument:- " + resultDocument);

Here, we first created the filter condition and based on that, either we'll update the existing document or add a new document to the collection vehicle.

5. Using the replaceOne Method

Let's perform the upsert operation using the replaceOne method. The replaceOne method of MongoDB just replaces the single document within the collection if the condition matches.

First, let's look into the Mongo shell query of the replace method:

db.vehicle.replaceOne(
{
    "modelName":"GTPR"
},
{
    "modelName" : "GTPR",
    "companyName" : "Hero Honda",
    "launchYear" : 2022,
    "type" : "Bike",
    "registeredNo" : "EPS 5562"
},
{
    "upsert":true
});

The above query will return the following response:

{ 
    "acknowledged" : true, 
    "matchedCount" : 1,
    "modifiedCount" : 1 
}

Now, let's write the above query using the Java driver code:

Document replaceDocument = new Document();
replaceDocument.append("modelName", "GTPP")
  .append("companyName", "Hero Honda")
  .append("launchYear", 2022)
  .append("type", "Bike")
  .append("registeredNo", "EPS 5562");
UpdateResult updateReplaceResult = collection.replaceOne(Filters.eq("modelName", "GTPP"), replaceDocument, options);
System.out.println("updateReplaceResult:- " + updateReplaceResult);

Here, in this case, we need first to create a new document by which we want to replace the existing document, and with the upsert option true, we'll replace the document only if the condition gets matched.

6. Conclusion

In this article, we've seen how to perform upsert operation with various update methods of MongoDB. First, we learned to execute the upsert with an update and findAndModify method and then use the replaceOne method. In short, we implemented the upsert operation using Mongo shell query and Java driver code.

The implementation of all the cases can be found over on GitHub.

NoSql Bottom

Build a Dashboard Using Cassandra, Astra, and Stargate

>> CHECK OUT THE ARTICLE
Persistence bottom
Get started with Spring Data JPA through the reference Learn Spring Data JPA course: >> CHECK OUT THE COURSE
Persistence footer banner
Comments are closed on this article!