spring data reactive mongodb

Spring Data Reactive MongoDB CRUD Example

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.

  • findBySkillsAll – We might want to search for people with all given skills.
  • findBySkillsIn – We might want to search for people containing 1 of the given skills.
@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:

  • Lets start the application to perform the various CRUD operations.
  • I register few freelancers as shown here using the POST endpoint.
{
    "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.

  • GET

  • PUT

  • Search By All skills

  • Search By one of the skills

  • DELETE

 

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:

4 thoughts on “Spring Data Reactive MongoDB CRUD Example

    1. I apologize. I did not do a good job of updating this. It is done now. Sorry for the confusion. Thanks for letting me know.

  1. Hi Vinoth, I am not clear on how to launch the express-mongo. I dont see anything is coming for http://localhost:8111

    % docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    d1deba17f473 mongo-express “tini — /docker-ent…” 15 minutes ago Up 13 minutes 8081/tcp, 0.0.0.0:8111->8111/tcp reactive-mongo-crud-mongo-express-1
    808ce3d1215c mongo “docker-entrypoint.s…” 15 minutes ago Up 15 minutes 0.0.0.0:27017->27017/tcp reactive-mongo-crud-mongo-1

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.