Site icon Vinsguru

Spring Data Reactive MongoDB CRUD Example

spring data reactive mongodb

Overview:

In this article, I would like to show how to perform various CRUD Operations with Spring Data Reactive MongoDB Repository.

Project Setup:

Lets first create a simple spring boot project with the required dependencies like Spring Data Reactive MongoDB.

Sample Application:

We are going to develop a simple spring boot application for freelancers in which the users can register themselves. So that people who want to hire freelancers can search with specific skill sets.

MongoDB Setup:

I use docker-compose to set up MongoDB.

version: "3"
services:
  mongo:
    image: mongo
    ports:
      - 27017:27017    
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: password
  mongo-express:
    image: mongo-express
    ports:
      - 8081:8081
    restart: always
    depends_on:
    - mongo
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: admin
      ME_CONFIG_MONGODB_ADMINPASSWORD: password
      ME_CONFIG_MONGODB_SERVER: mongo

Entity:

The entity class is designed as below. I use lombok for the getters and setters.

@Data
@Document
@ToString
public class Freelancer {

    @Id
    private String id;
    private String name;
    private int age;
    private List<String> skills;

}

Spring Data Reactive MongoDB Repository:

We create a repository to do basic CRUD Operations by extending ReactiveMongoRepository.  We also add couple of methods to the interface for searching with specific skill sets.

@Repository
public interface FreelancerRepository extends ReactiveMongoRepository<Freelancer, String> {

    @Query("{ 'skills': { $all: ?0 } }")
    Flux<Freelancer> findBySkillsAll(List<String> skills);

    Flux<Freelancer> findBySkillsIn(List<String> skills);

}

Service:

Let’s create a service class for the CRUD operations and for the above search functionality.

@Service
public class FreelancerService {

    @Autowired
    private FreelancerRepository repository;

    public Flux<Freelancer> findBySkillsOne(final List<String> skills){
        return this.repository.findBySkillsIn(skills);
    }

    public Flux<Freelancer> findBySkillsAll(final List<String> skills){
        return this.repository.findBySkillsAll(skills);
    }

    public Mono<Freelancer> getPerson(final String id){
        return this.repository.findById(id);
    }

    public Mono<Freelancer> savePerson(final Freelancer person){
        return this.repository.save(person);
    }

    public Mono<Freelancer> updatePerson(final Freelancer person){
        return this.repository.findById(person.getId())
                    .map(p -> person)
                    .flatMap(this.repository::save);
    }

    public Mono<Void> deletePerson(final String id){
        return this.repository.deleteById(id);
    }

}

REST Controller:

Lest create the controller as shown here. Do note that when we use reactive driver nothing happens until we subscribe to that action. If you notice, even a delete method which could have been ‘void’ return type returns a Mono<Void>.  If you want the return type to be void, ensure that you are subscribing to that Flux / Mono from the Spring Data Reactive MongoDB repository. Otherwise it will not work. I directly expose entity class for this demo. In real life you might want to use a DTO.

@RestController
public class FreelancerController {

    @Autowired
    private FreelancerService freelancerService;

    @GetMapping("/person/skills-one/{skills}")
    public Flux<Freelancer> findBySkills(@PathVariable List<String> skills){
        return this.freelancerService.findBySkillsOne(skills);
    }

    @GetMapping("/person/skills-all/{skills}")
    public Flux<Freelancer> findByAllSkills(@PathVariable List<String> skills){
        return this.freelancerService.findBySkillsAll(skills);
    }

    @GetMapping("/person/{id}")
    public Mono<Freelancer> getPerson(@PathVariable String id){
        return this.freelancerService.getPerson(id);
    }

    @PostMapping("/person")
    public Mono<Freelancer> createPerson(@RequestBody Freelancer person){
        return this.freelancerService.savePerson(person);
    }

    @PutMapping("/person")
    public Mono<Freelancer> updatePerson(@RequestBody Freelancer person){
        return this.freelancerService.updatePerson(person);
    }
    
    @DeleteMapping("/person/{id}")
    public Mono<Void> deletePerson(@PathVariable String id){
        return this.freelancerService.deletePerson(id);
    }

}

Application Properties:

spring.data.mongodb.database=admin
spring.data.mongodb.username=admin
spring.data.mongodb.password=password

CRUD Operations:

{
    "name": "sam",
    "age": 40,
    "skills": [ "js", "react", "python"]
}

{
    "name": "jack",
    "age": 38,
    "skills": [ "js", "angular", "postgres"]
}

{
    "name": "james",
    "age": 30,
    "skills": [ "java", "reactor", "mongo"]
}

{
    "name": "smith",
    "age": 32,
    "skills": [ "qa", "selenium"]
}

We should be able to view all the records via Mongo express at port 8081.

 

Summary:

We were able to do simple CRUD operations with Spring Data Reactive MongoDB Repository easily as Spring Data does all the heavy lifting.

You can find the source code here.

Learn more about MongoDB + Reactive Spring Data here.

Happy learning 🙂

Share This:

Exit mobile version