SpringData Reactive MongoDB Repositories | SpringBoot

Reactive programming is about non-blocking applications. With the previous post, we had learned how to use SpringBoot WebFlux. In the tutorial, JavaSampleApproach will explore more about SpringData Reactive MongoDB Repositories with a set of high-level abstraction CRUD methods.

Related posts:
SpringBoot WebFlux Annotation-based RestAPIs
SpringBoot WebFlux Functional RestAPIs
SpringData Reactive Cassandra Repositories | SpringBoot
Angular 4 + Spring Boot + MongoDB CRUD example
– Full Reactive: Angular 4 + Spring WebFlux + Spring Data Reactive MongoDB example

I. Technologies

– Java: 1.8
– Maven: 3.3.9
– Spring Tool Suite: Version 3.9.0.RELEASE
– Spring Boot: 2.0.0.M4
– Spring Boot Starter Webflux
– Spring Boot Starter Data Mongodb Reactive
– MongoDb – v3.4.9

II. SpringData Reactive MongoDb

MongoDB Reactive SpringData provides repositories with a set of high-level abstraction CRUD methods or templates for working. In the tutorial, we focus on Reactive MongoDB repositories implementation.

For working with ReactiveMongodb, we need dependency:


	org.springframework.boot
	spring-boot-starter-data-mongodb-reactive

How to work?

We use AbstractReactiveMongoConfiguration to configure Reactive MongoDB database:

...

@EnableReactiveMongoRepositories
public class MongoDbReactiveConfig extends AbstractReactiveMongoConfiguration {
	@Override
	public MongoClient reactiveMongoClient() {
		return MongoClients.create();
	}

	@Override
	protected String getDatabaseName() {
		return "test";
	}
}

We use ReactiveCrudRepository to define reactive-repositories:

public interface ReactiveCustomerRepository extends ReactiveCrudRepository {
	
	@Query("{ 'firstname': ?0, 'lastname': ?1}")
	Mono findByFirstnameAndLastname(String firstname, String lastname);
	
	Flux findByAge(Mono age);
}
We can pass parameters to query methods as plain (e.g. String), wrapped (Optional, Stream) or reactive wrapped arguments (Mono, Flux).
When using reactive wrappers (Mono, Flux) parameters, query creation and execution will be defered until having an actual subscription.

We can combine Spring Web Reactive and SpringData Reactive in a reactive processing way:

...

@GetMapping
public Flux getAll() {
	
	// retrieve all
	return reactiveCustomerRepo.findAll();
}

@GetMapping("/{id}")
public Mono getCustomerById(@PathVariable Long id) {
	
	// find by id
	return reactiveCustomerRepo.findById(id);
}

...

III. Practice

We create a SpringBoot project as below:

springdata mongodb reactive - project structure

Step to do:
– Create SpringBoot project
– Create data model
– Configure MongoDb Reactive
– Implement Reactive repository
– Implement WebFlux RestAPIs
– Implement initial client
– Run and check results

1. Create SpringBoot project

Using SpringToolSuite to create SpringBoot project, then add needed dependencies:

springdata mongodb reactive - add needed dependencies

Check pom.xml file after finishing:

...


	org.springframework.boot
	spring-boot-starter-data-mongodb-reactive


	org.springframework.boot
	spring-boot-starter-webflux


...
2. Create data model

Create Customer data class:

package com.javasampleapproach.mongodbreactive.model;

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

@Document(collection="customer")
public class Customer {
	
	@Id
	private long custId;
	private String firstname;
	private String lastname;
	private int age;
	
	public Customer(long custId, String firstname, String lastname, int age){
		this.custId = custId;
		this.firstname = firstname;
		this.lastname = lastname;
		this.age = age;
	}
 
	public long getCustId() {
		return custId;
	}
 
	public void setCustId(Long custId) {
		this.custId = custId;
	}
 
	public String getFirstname() {
		return firstname;
	}
 
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
 
	public String getLastname() {
		return lastname;
	}
 
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
 
	public int getAge() {
		return age;
	}
 
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public String toString() {
		String info = String.format("custId = %d, firstname = %s, lastname = %s, age = %d", custId, firstname, lastname, age);
		return info;
	}
}
3. Configure MongoDb Reactive
package com.javasampleapproach.mongodbreactive.config;

import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;

import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;

@EnableReactiveMongoRepositories
public class MongoDbReactiveConfig extends AbstractReactiveMongoConfiguration {

	@Override
	public MongoClient reactiveMongoClient() {
		return MongoClients.create();
	}

	@Override
	protected String getDatabaseName() {
		return "test";
	}

}

4. Implement Reactive repository
package com.javasampleapproach.mongodbreactive.repo;

import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;

import com.javasampleapproach.mongodbreactive.model.Customer;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface ReactiveCustomerRepository extends ReactiveCrudRepository {
	
	@Query("{ 'firstname': ?0, 'lastname': ?1}")
	Mono findByFirstnameAndLastname(String firstname, String lastname);
	
	Flux findByAge(Mono age);
}
5. Implement WebFlux RestAPIs
package com.javasampleapproach.mongodbreactive.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.javasampleapproach.mongodbreactive.model.Customer;
import com.javasampleapproach.mongodbreactive.repo.ReactiveCustomerRepository;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping(value="/api/customer")
public class RestControllerAPIs {
	
	@Autowired
	ReactiveCustomerRepository reactiveCustomerRepo;

	@GetMapping
    public Flux getAll() {
		
		// retrieve all
    	return reactiveCustomerRepo.findAll();
    }
	
	@GetMapping("/{id}")
    public Mono getCustomerById(@PathVariable Long id) {
		
		// find by id
		return reactiveCustomerRepo.findById(id);
    }
	
	@GetMapping("/findbynames")
	public Mono findByFirstnameAndLastname(@RequestParam String firstname, @RequestParam String lastname){
		
		// find on MongoDB
		return reactiveCustomerRepo.findByFirstnameAndLastname(firstname, lastname);
	}
	
	@GetMapping("/findbyage")
	public Flux findByAge(@RequestParam int age){
		
		// find on MongoDB
		Flux customers = reactiveCustomerRepo.findByAge(Mono.just(age));
		
		// transform data
		return customers.map(it -> " - " + it.getFirstname() + " " + it.getLastname() + "
"); } }

Open application.properties file to add a configuration for Pretty-print JSON responses:

# Pretty-print JSON responses
spring.jackson.serialization.indent_output=true
6. Implement initial client
package com.javasampleapproach.mongodbreactive;

import java.util.Arrays;

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

import com.javasampleapproach.mongodbreactive.model.Customer;
import com.javasampleapproach.mongodbreactive.repo.ReactiveCustomerRepository;

@SpringBootApplication
public class SpringMongoDbReactiveRepositoriesApplication implements CommandLineRunner{
	
	@Autowired
	ReactiveCustomerRepository reactiveCustomerRepo;
	
	public static void main(String[] args) {
		SpringApplication.run(SpringMongoDbReactiveRepositoriesApplication.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		
		// save list Customers
		reactiveCustomerRepo.saveAll(Arrays.asList(new Customer(new Long(1), "Walter", "White", 29),
										  new Customer(new Long(2), "Skyler", "White", 24),
										  new Customer(new Long(3), "Saul", "Goodman", 27),
										  new Customer(new Long(4), "Jesse", "Pinkman", 24)
										)
									).subscribe(System.out::println);
	}
}

7. Run and check results

Build and run the SpringBoot project with commandlines {mvn clean install, mvn spring-boot:run}

-> MongoDb’s documents:

springdata mongodb reactive - all customer in mongo db

– Make a request to get all customers http://localhost:8080/api/customer

springdata mongodb reactive - get all request

– Make a request to get a customer by id http://localhost:8080/api/customer/2

springdata mongodb reactive - get by id

– Make a request to get list full name of customers by age http://localhost:8080/api/customer/findbyage?age=24

springdata mongodb reactive - get by age

– Make a request to get a Customer by full name http://localhost:8080/api/customer/findbynames?firstname=Skyler&lastname=White

springdata mongodb reactive - find by names

IV. Sourcecode

SpringMongoDbReactiveRepositories



By grokonez | September 23, 2017.

Last updated on March 16, 2018.



Related Posts


Got Something To Say:

Your email address will not be published. Required fields are marked *

*