MongoDB Data Migrations In Spring Boot

If you are running Spring Boot applications that use MongoDB in production, chances are that your data model evolved over time. And it will likely change in the future. Applying migrations is essential to keep the data consistent and your project running gracefully over time. There are many ways to handle data migrations for MongoDB, but if you are using Spring, then the easiest one is with a library called Mongobee. If you have ever used Liquibase or Flyway, than you will feel confortable with Mongobee.

In this post, I’ll show you how to create database change-sets using this library, in an existing Spring Boot application.

Step 1: Add the MongoBee dependency

<!-- Mongo Migrations -->
<dependency>
    <groupId>com.github.mongobee</groupId>
    <artifactId>mongobee</artifactId>
    <version>0.13</version>
</dependency>

Step 2: Configure the  Mongobee runner

Next, you need to create the MongoBee runner bean. One way to do it is the following:

  • Define the Mongobee bean by providing correct connection details and the package(s) where the data migration classes exist
  • Optionally you can pass in a MongoTemplate instance if you want to use it in the migration classes
@SpringBootApplication
public class LegostoreApplication {

    public static void main(String[] args) {
        SpringApplication.run(LegostoreApplication.class, args);
    }

    @Autowired
    MongoTemplate mongoTemplate;

    @Bean
    public Mongobee mongobee() {
        // Add the correct connection settings
        Mongobee runner = new Mongobee("mongodb://localhost:27017/legostore");
        
        // If you need to have access to the MongoTemplate class,
        // you need to pass it in
        runner.setMongoTemplate(mongoTemplate);
        
        // Note that the runner will scan the 'rc.legostore.persistence'
        // package for data migration classes
        runner.setChangeLogsScanPackage("rc.legostore.persistence");

        return runner;
    }
}

Step 3: Create a data migration change-set

MongoBee defines the following constructs for enabling migrations:

  • A change-set is a migration unit.
  • A change-log is a collection of change-sets, preferably related.

For example, if you release version 2.2 of your software, you can create a change log that will contain all the atomic change-sets that were done since version 2.1 In code, we can use the @ChangeLog and @ChangeSet annotations to mark classes and methods. You can optionally provide an order if this is important.

package rc.legostore.persistence;

@ChangeLog(order = "001")
public class DataMigrations {

    @ChangeSet(order = "001", author = "dan", id = "update nb parts")
    public void updateNbParts(MongoTemplate mongoTemplate) {
        Criteria priceZeroCriteria = new Criteria().orOperator(
                Criteria.where("nbParts").is(0),
                Criteria.where("nbParts").is(null));

        mongoTemplate.updateMulti(
                new Query(priceZeroCriteria),
                Update.update("nbParts", 122),
                LegoSet.class);

        System.out.println("Applied changeset 001");
    }

    @ChangeSet(order = "002", author = "dan", id = "insert additional payment method")
    public void insertAdditionalPaymentOption(MongoTemplate mongoTemplate) {
        PaymentOptions bankTransferPayment = new PaymentOptions(PaymentType.BankTransfer, 1);
        mongoTemplate.insert(bankTransferPayment);
    }
}

Note that the DataMigrations class is defined in the “rc.legostore.persistence” package, which is the same as the package that the Mongobee runner is configured to scan.

Step 4: Run your application

You can now run the application and see that all the migrations have been applied. Mongobee has the following behavior:

  • It generates additional collections, where it keeps the current database level
  • It checks the current database level with the migrations found during in your code
  • It applies (in correct order) the missing change sets