There are plenty of online guides explaining how to configure a Spring Boot application that connects to multiple MongoDBs. The common approach was to use MongoDbFactory, but this class has been deprecated Spring Data MongoDB 3.x which introduced the MongoDB 4.x driver.

So, what to do now?

Let’s see how to configure multiple MongoDB data sources in Spring Boot using Spring Data MongoDB 3.x.

Please, note that code will be written in Kotlin, but the same result can be achieved in Java as well. Similarly, I am going to use only two different MongoDB connections in this tutorial, but the approach works with any number of databases.


1. Adding the Required Dependencies

First of all, you have to add spring-boot-starter-data-mongodb to your project’s dependencies. You need at least the 2.3.0 version since the MongoDB Driver 4.x was introduced in Spring Boot Starter Data MongoDB 2.3.0.RELEASE.

If you are a Gradle user, add this dependency to your project’s build file:

compile "org.springframework.boot:spring-boot-starter-data-mongodb:2.3.0.RELEASE"

Otherwise, if you are a Maven user, add the following dependency to your project’s build POM:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-mongodb</artifactId>
   <version>2.3.0.RELEASE</version>
</dependency>

Now, you have all you need to use MongoDB in Spring Boot.


2. Defining Multiple MongoTemplate Instances

If you have already defined multiple MongoTemplate but you want to upgrade to Spring Data MongoDB 3.x, I recommend reading this first. Otherwise, you can start from scratch following the next few steps.

First of all, you need to define all your MongoDB connection details in your application.properties.

host and port configurations are no longer supported in the MongoDB 4.x driver, so you need to use a single URI providing all of the required configurations with this format:

mongodb://<username>:<password>@<host>:<port>/<db_name>

Please note that <username>:<password>@ is optional and you should use it only for an authenticated connection. So, your application.properties should contain something like this:

#--- Primary MongoDB ---#
spring.data.mongodb.uri=mongodb://admin:root@127.0.0.1:27017/primary
#--- Secondary MongoDB ---#
mongodb.uri=mongodb://admin:root@127.0.0.1:27017/secondary

Now, it is time to add a new configuration file, where to define one MongoTemplate Spring Boot bean for each connection.

@Configuration
class MultipleMongoConfig {
   @Primary
   @Bean(name = ["primaryMongoProperties"])
   @ConfigurationProperties(prefix = "spring.data.mongodb")
   fun getPrimary() : MongoProperties {
       return MongoProperties()
   }
   @Bean(name = ["secondaryMongoProperties"])
   @ConfigurationProperties(prefix = "mongodb")
   fun getSecondary() : MongoProperties {
       return MongoProperties()
   }
   @Primary
   @Bean(name = ["primaryMongoTemplate"])
   fun primaryMongoTemplate() : MongoTemplate {
       return MongoTemplate(primaryMongoDatabaseFactory(getPrimary()))
   }
   @Bean(name = ["secondaryMongoTemplate"])
   fun secondaryMongoTemplate() : MongoTemplate {
       return MongoTemplate(secondaryMongoDatabaseFactory(getSecondary()))
   }
   @Primary
   @Bean
   fun primaryMongoDatabaseFactory(mongo : MongoProperties) : MongoDatabaseFactory {
       return SimpleMongoClientDatabaseFactory(
           mongo.uri
       )
   }
   @Bean
   fun secondaryMongoDatabaseFactory(mongo : MongoProperties) : MongoDatabaseFactory {
       return SimpleMongoClientDatabaseFactory(
           mongo.uri
       )
   }
}

The @ConfigurationProperties annotation works with hierarchical properties that all have the same prefix defined in your configuration file. Spring Boot will automatically bind any property defined in the application.properties file that has the prefix declared in the annotation and the same name as one of the fields in the target class. This means that the uri field of the MongoProperties objects will have the value read from your configuration file.

The MongoProperties instances are used to establish the connections to the databases through SimpleMongoClientDatabaseFactory and then create the required MongoTemplate instances.

The MongoTemplate class is the primary implementation of the MongoOperations interface and provides a basic set of MongoDB operations. You can use a MongoTemplate object to do aggregations, sorting, and finding the desired documents based on multiple criteria in the database it refers to.

Lastly, you have to disable Spring Boot autoconfiguration for Mongo. You can achieve this by adding these lines of code on top of your Spring Boot application’s main class:

@SpringBootApplication(exclude = [
  MongoAutoConfiguration::class,
  MongoDataAutoConfiguration::class
])

3. Using the MongoTemplate Instances

Using MongoTemplate Directly

MongoTemplate provides a basic API to the underlying persistence engine and can be used to execute queries. All you need to use it in such a way is a working instance.

Let’s assume you want to retrieve all the authors saved in a collection named authors placed in the secondary MongoDB database by a specific surname. First of all, you need an Author class annotated with @Document representing the documents stored in the collection:

@Document(collection = "author")
class Author {
   @get:Id
   @get:Field("_id")
   var id: String? = null

   @get:Field("name")
   var name: String? = null

   @get:Field("surname")
   var surname: String? = null
}

Then, in a DAO layer class, you can define the retrieving logic as follows:

@Repository
class AuthorDao {
   @Autowired
   @Qualifier("secondaryMongoTemplate")
   protected lateinit var secondaryMongoTemplate : MongoTemplate

   fun findBySurname(surname): List<Author> {
       val query = Query()

      query.addCriteria(
          Criteria.where("surname").`is`(surname)
      )
      return secondaryMongoTemplate.find(query, Author::class.java)
   }
}

Notice that the @Qualifier annotation is required to select the desired MongoTemplate instance by Bean name. Without it, Spring Boot would choose the primaryMongoTemplate object defined in MultipleMongoConfig because it is marked with @Primary.

Et voila! No other lines of code are required.

Using MongoTemplate through MongoRepository

Repositories are one of the main concepts of Spring Data and a way to reduce the effort to implement data access layers by avoiding boilerplate code. For further reading, I recommend this.

The implementation class of MongoRepository harnesses a MongoTemplate instance at run time. To specify which MongoTemplate bean has to be used, you need extra configurations. In particular, you have to define a new @Configuration file for each MongoTemplate instance.

This is what the configuration file to enable repositories working with primaryMongoTemplate looks like:

@Configuration
@EnableMongoRepositories(
   basePackages = ["com.example.yourproject.primary.repositories"],
   mongoTemplateRef = "primaryMongoTemplate"
)
class PrimaryMongoDBRepositoryConfig

And this is what the configuration file to enable repositories working with secondaryMongoTemplate looks like:

@Configuration
@EnableMongoRepositories(
   basePackages = ["com.example.yourproject.secondary.repositories"],
   mongoTemplateRef = "secondaryMongoTemplate"
)
class SecondarMongoDBRepositoryConfig

Please note that basePackages must point to the packages where all your repositories related to a specific mongoTemplateRef are placed. Now you have all you need to start using MongoDB repositories in Spring Boot. This article is not aimed at showing it and I suggest reading this instead.


Conclusion

Here we looked at how to define multiple MongoTemplate using the MongoDB 4.x driver in Spring Boot from the ground up. At the same time, I showed how to use them directly or through MongoRepository to execute all the queries you need to retrieve and persist data.

Thanks for reading! I hope that you found this article helpful. Feel free to reach out to me for any questions, comments, or suggestions.