Multiple MongoDB Connectors With Spring Boot

This tutorial will guide you in the process to connect to multiple MongoDBs.

What You Will Build

You will build an application that connects to multiple MongoDBs.

Prerequisites

The sample project uses Project Lombok to generate getters, setters, contructors, etc.

Spring Boot MongoDB Connection

To create a MongoTemplate instance through Spring Boot, we only need to provide Mongo Server details in Spring Boot specific property keys and Spring Boot on startup automatically creates a Mongo Connection with MongoTemplate wrapper and lets us auto wire wherever we want to use.

Below are the basic properties required for creating a MongoTemplate.

spring:
  data.mongodb:
    host: # hostname
    port: # port
    uri: #uri
    database: #db

Spring Boot has a class called MongoProperties.java, which defines the mandatory property key prefix as spring.data.mongodb (can be seen in the above properties extract). The MongoProperties.java holds all the mongo properties that we wrote in the application.yml. Then there is another class called as MongoDataAutoConfiguration.java which uses the MongoProperties.java as its Properties Configuration Class and is responsible for actually creating the MongoTemplate through one of its factory methods.

To connect to two different mongo servers, it’s required to override all these classes and their behaviors.

Disabling Spring Boot AutoConfig

To be able to create multiple MongoTemplate objects, it’s necessary to disable the Spring Boot autoconfig for MongoDB. It can be achieved just by adding the following property in the application.yml file.

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration

Configuring Multiple MongoTemplates

First of all, create the following @ConfigurationProperties class.

src/main/java/com/marcosbarbero/wd/multiplemongo/config/MultipleMongoProperties

import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;

import lombok.Data;

@Data
@ConfigurationProperties(prefix = "mongodb")
public class MultipleMongoProperties {

    private MongoProperties primary = new MongoProperties();
    private MongoProperties secondary = new MongoProperties();
}

And then add the following properties in the application.yml

mongodb:
  primary:
    host: localhost
    port: 27017
    database: second
  secondary:
    host: localhost
    port: 27017
    database: second

Now it’s necessary to create the MongoTemplates to bind the given configuration in the previous step.

src/main/java/com/marcosbarbero/wd/multiplemongo/config/MultipleMongoConfig

package com.marcosbarbero.wd.multiplemongo.config;

import com.mongodb.MongoClient;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;

import lombok.RequiredArgsConstructor;

@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(MultipleMongoProperties.class)
public class MultipleMongoConfig {

    private final MultipleMongoProperties mongoProperties;

    @Primary
    @Bean(name = "primaryMongoTemplate")
    public MongoTemplate primaryMongoTemplate() throws Exception {
        return new MongoTemplate(primaryFactory(this.mongoProperties.getPrimary()));
    }

    @Bean(name = "secondaryMongoTemplate")
    public MongoTemplate secondaryMongoTemplate() throws Exception {
        return new MongoTemplate(secondaryFactory(this.mongoProperties.getSecondary()));
    }

    @Bean
    @Primary
    public MongoDbFactory primaryFactory(final MongoProperties mongo) throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(mongo.getHost(), mongo.getPort()),
                mongo.getDatabase());
    }

    @Bean
    public MongoDbFactory secondaryFactory(final MongoProperties mongo) throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(mongo.getHost(), mongo.getPort()),
                mongo.getDatabase());
    }

}

With the configuration above, you’ll be able to have two different MongoTemplates based on the custom configuration properties that we provided previously in this guide.

Using Multiple Templates

In the previous step, we created two MongoTemplates, primaryMongoTemplate and secondaryMongoTemplate. In this section, we’ll make some data model and make it all work together.

Creating the Data Model and Repositories

First, we will create two data models to access different collections.

src/main/java/com/marcosbarbero/wd/multiplemongo/repository/primary/PrimaryModel

package com.marcosbarbero.wd.multiplemongo.repository.primary;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "first_mongo")
public class PrimaryModel {

@Id
private String id;

private String value;

@Override
public String toString() {
        return "PrimaryModel{" + "id='" + id + '\'' + ", value='" + value + '\''
+ '}';
}
}

src/main/java/com/marcosbarbero/wd/multiplemongo/repository/secondary/SecondaryModel

package com.marcosbarbero.wd.multiplemongo.repository.secondary;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "second_mongo")
public class SecondaryModel {

    @Id
    private String id;

    private String value;

    @Override
    public String toString() {
        return "SecondaryModel{" + "id='" + id + '\'' + ", value='" + value + '\''
                + '}';
    }
}

Now we’ll need to create one repository per data model.

src/main/java/com/marcosbarbero/wd/multiplemongo/repository/primary/PrimaryRepository

package com.marcosbarbero.wd.multiplemongo.repository.primary;

import org.springframework.data.mongodb.repository.MongoRepository;

public interface PrimaryRepository extends MongoRepository<PrimaryModel, String> {

}

src/main/java/com/marcosbarbero/wd/multiplemongo/repository/secondary/SecondaryRepository

package com.marcosbarbero.wd.multiplemongo.repository.secondary;

import org.springframework.data.mongodb.repository.MongoRepository;

public interface SecondaryRepository extends MongoRepository<SecondaryModel, String> {

}

Enabling Mongo Repositories

Now, we already have the properties configuration classes and data model classes, so we need to configure which MongoTemplate will be responsible for each defined repository.

src/main/java/com/marcosbarbero/wd/multiplemongo/config/PrimaryMongoConfig

package com.marcosbarbero.wd.multiplemongo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

@Configuration
@EnableMongoRepositories(basePackages = "com.marcosbarbero.wd.multiplemongo.repository.primary",
        mongoTemplateRef = "primaryMongoTemplate")
public class PrimaryMongoConfig {

}

src/main/java/com/marcosbarbero/wd/multiplemongo/config/SecondaryMongoConfig

package com.marcosbarbero.wd.multiplemongo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

@Configuration
@EnableMongoRepositories(basePackages = "com.marcosbarbero.wd.multiplemongo.repository.secondary",
        mongoTemplateRef = "secondaryMongoTemplate")
public class SecondaryMongoConfig {

}

Running

To test the application, I just added the following code to the main class in the project.

src/main/java/com/marcosbarbero/wd/multiplemongo/Application

package com.marcosbarbero.wd.multiplemongo;

import com.marcosbarbero.wd.multiplemongo.repository.primary.PrimaryModel;
import com.marcosbarbero.wd.multiplemongo.repository.primary.PrimaryRepository;
import com.marcosbarbero.wd.multiplemongo.repository.secondary.SecondaryModel;
import com.marcosbarbero.wd.multiplemongo.repository.secondary.SecondaryRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.List;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private PrimaryRepository primaryRepository;

    @Autowired
    private SecondaryRepository secondaryRepository;

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

    @Override
    public void run(String... args) throws Exception {
        log.info("************************************************************");
        log.info("Start printing mongo objects");
        log.info("************************************************************");
        this.primaryRepository.save(new PrimaryModel(null, "Primary database plain object"));

        this.secondaryRepository.save(new SecondaryModel(null, "Secondary database plain object"));

        List<PrimaryModel> primaries = this.primaryRepository.findAll();
        for (PrimaryModel primary : primaries) {
            log.info(primary.toString());
        }

        List<SecondaryModel> secondaries = this.secondaryRepository.findAll();

        for (SecondaryModel secondary : secondaries) {
            log.info(secondary.toString());
        }

        log.info("************************************************************");
        log.info("Ended printing mongo objects");
        log.info("************************************************************");

    }
}

As this project was built using Spring Boot, to run it, just execute the following commands:

Build

$ ./mvnw clean package

Run

$ java -jar target/multiple-mongo-connectors-0.0.1-SNAPSHOT.jar

The process prints the following output:

************************************************************
Start printing mongo objects
************************************************************
Opened connection [connectionId{localValue:3, serverValue:11}] to localhost:27017
Opened connection [connectionId{localValue:4, serverValue:12}] to localhost:27017
PrimaryModel{id='5a8834ee536b1d604345da4e', value='Primary database plain object'}
SecondaryModel{id='5a884cc8536b1da4468466a7', value='Secondary database plain object'}
************************************************************
Ended printing mongo objects
************************************************************

This guide requires a MongoDB instance up and running in localhost and 27017port.

Summary

Congratulations! You just created a Spring Boot project that connects to multiple MongoDB instances.

Footnote

 

 

 

 

Top