Spring Reactive Multi MongoTemplate Configuration

Why Multi MongoTemplate Configuration?

What do we need to solve?

  • How do we define our Database Properties?
  • How do we does the repository differentiate which Database to interact with?
  • How do we configure DB options?

Defining MongoDB Properties

application.yml

spring:
data:
mongodb:
coffee:
database: coffee
uri: mongodb://localhost:27017
burger:
database: burger
uri: mongodb://localhost:27017
autoconfigure:
exclude: org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration

Reading the Config file

package com.acme.multimongo.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties(prefix = "spring.data.mongodb")
@Getter
@Setter
public class CustomMongoProperties {
private MongoProperties coffee;
private MongoProperties burger;

}

Define The Configuration

  • MongoConfig
  • MongoTemplate
  • MongoClient

Defining the Mongo Config

package com.acme.multimongo.config;

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


@Configuration
@EnableReactiveMongoRepositories(basePackages = "com.acme.multimongo.repository.burger",
reactiveMongoTemplateRef = "mongoTemplateBurger")

public class BurgerMongoConfig {
}
package com.acme.multimongo.config;

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


@Configuration
@EnableReactiveMongoRepositories(basePackages = "com.acme.multimongo.repository.coffee",
reactiveMongoTemplateRef = "mongoTemplateCoffee")

public class CoffeeMongoConfig {
}

Defining MongoClient and MongoTemplates

@Primary
@Bean
public MongoClient reactiveMongoClientCoffee() {
return MongoClients.create(createMongoClientSettings(customMongoProperties.getCoffee()));
}
@Primary
@Bean("mongoTemplateCoffee")
public ReactiveMongoTemplate reactiveMongoTemplateCoffee(){
return new ReactiveMongoTemplate(reactiveMongoClientCoffee(),customMongoProperties.getCoffee().getDatabase());
}

private MongoClientSettings createMongoClientSettings(MongoProperties mongoProperties){

ConnectionString ConnectionString = new ConnectionString(mongoProperties.getUri());

MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.readConcern(ReadConcern.DEFAULT)
.writeConcern(WriteConcern.MAJORITY)
.readPreference(ReadPreference.primary())
.applyConnectionString(ConnectionString)
.build();
return mongoClientSettings;
}
package com.acme.multimongo.config;

import com.mongodb.*;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;

@Configuration
public class MongoConfiguration {

private final CustomMongoProperties customMongoProperties;

public MongoConfiguration(CustomMongoProperties customMongoProperties) {
this.customMongoProperties = customMongoProperties;
}

@Primary
@Bean
public MongoClient reactiveMongoClientCoffee() {
return MongoClients.create(createMongoClientSettings(customMongoProperties.getCoffee()));
}

@Bean
public MongoClient reactiveMongoClientBurger() {
return MongoClients.create(createMongoClientSettings(customMongoProperties.getBurger()));
}

@Primary
@Bean("mongoTemplateCoffee")
public ReactiveMongoTemplate reactiveMongoTemplateCoffee(){
return new ReactiveMongoTemplate(reactiveMongoClientCoffee(),customMongoProperties.getCoffee().getDatabase());
}
@Bean("mongoTemplateBurger")
public ReactiveMongoTemplate reactiveMongoTemplateBurger(){
return new ReactiveMongoTemplate(reactiveMongoClientBurger(),customMongoProperties.getBurger().getDatabase());
}


private MongoClientSettings createMongoClientSettings(MongoProperties mongoProperties){

ConnectionString ConnectionString = new ConnectionString(mongoProperties.getUri());

MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.readConcern(ReadConcern.DEFAULT)
.writeConcern(WriteConcern.MAJORITY)
.readPreference(ReadPreference.primary())
.applyConnectionString(ConnectionString)
.build();
return mongoClientSettings;
}
}

Using these Configuration in a simple class

package com.acme.multimongo;

import com.acme.multimongo.repository.burger.BurgerStoreRepository;
import com.acme.multimongo.repository.burger.StoreEntity;
import com.acme.multimongo.repository.coffee.CoffeeShopRepository;
import com.acme.multimongo.repository.coffee.ShopEntity;
import java.util.List;
import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.reactive.config.EnableWebFlux;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@SpringBootApplication
@EnableWebFlux
public class MultimongoApplication implements CommandLineRunner {

@Autowired
private BurgerStoreRepository burgerStoreRepository;
@Autowired
private CoffeeShopRepository coffeeShopRepository;



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

@Override
public void run(String ... args) {
Mono<List<StoreEntity>> storeList = this.testStore();
Mono<List<ShopEntity>> cafeList = this.testCafe();

storeList.then(cafeList).subscribe();
}

protected Mono<List<StoreEntity>> testStore(){
Mono storeDeleteMono = this.burgerStoreRepository.deleteAll();


Mono<List<StoreEntity>> rsp = storeDeleteMono
.thenMany(
Flux.just("BK","MCD","FG")
.map(name -> new StoreEntity(name,new Random().nextInt()%10))
.flatMap(burgerStoreRepository::save)
).thenMany(burgerStoreRepository.findAll())
.collectList();

return rsp;


}
protected Mono<List<ShopEntity>> testCafe(){
Mono shopDeleteMono = this.coffeeShopRepository.deleteAll();


return shopDeleteMono
.thenMany(
Flux.just("SB","DD","TH")
.map(name -> new ShopEntity(name,new Random().nextInt()%10))
.flatMap(coffeeShopRepository::save)
).thenMany(coffeeShopRepository.findAll())
.collectList();
}


}

References

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Visweshwar Ganesh

Visweshwar Ganesh

22 Followers

Developer, Solution Lead @Paychex. Always look for opportunities to innovate and explore. Twitter: @visweshwar.LinkedIn: visweshwar-ganesh-5797405