In this tutorial, we will learn to integrate MongoDB with a spring boot application and perform different CRUD operations through Spring Data MongoRepository as well as MongoTemplate with different examples and samples. The different CRUD operations such as Create, Read, Update and Delete will be first implemented through MongoRepository and the same operations will be again implemented in MongoTemplate to provide the implementation differences between both the approaches. Also, we will have the REST endpoints exposed to perform these operations. Hence, we are going to develop an end to end spring boot MongoDB example app to perform different CRUD operations.
In this tutorial, we will be developing the sample app with Spring Boot 2 i.e. 2.1.6.RELEASE and hence the MongoDB driver version will be 3+ i.e. 3.8.2
We will have two entities defined as Department and Employee with one to many relationships - one department can have multiple employees. We will not be using @DBRef to visualise relational mapping kind of mapping as it does not fits well in NoSQL paradigm. You can refer this article that provides a good reason for this. Hence, we will be using embedded relations. But our repository implementation will have a mechanism to fetch all the employees by department or fetch department by employee name.
Spring Boot MongoDB Project Setup
Let us configure our Spring Boot app to use MongoDB first.
Spring Boot MongoDB Maven Dependencies
First let us start with defining our dependencies. As we will be using Maven, below is our pom.xml.
pom.xml<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
Project Stucture
Below is our project structure.
Spring Boot MongoDB Properties Configuration
With Mongo 3.0 Java driver, spring.data.mongodb.host
and spring.data.mongodb.port
are not supported. In such cases, spring.data.mongodb.uri should be used to provide all of the configuration. Hence, below is our configuration file with spring.data.mongodb.uri
spring.data.mongodb.uri=mongodb://root:root@localhost:27017/test_db logging.level.root=DEBUG
As per our configuration, Mongo DB is running locally at default port 27017. We are using test_db database with this example and root is the username/password to access the same. If your Mongo process is not started with mongod --auth
, then it is not required to provide the username and password.
With this much configuration and spring-boot-starter-data-mongodb
at the classpath, Spring creates an instance of MongoTemplate and available for autowiring.
If we want to customize our MongoTemplate default bean then we can go ahead with java configurations for the same.
MongoDB Model Implementation
As we discussed above, we have a one-many relationship between Department and Employee model, the Department.java definition will have a list of employees in it.
Department.java@Document("Department") public class Department { @Id private String id; @Indexed(name = "deptName") private String name; private String description; //@DBRef private Listemployees; //getters and setters
Document
identifies a domain object to be persisted to MongoDB.
@Id
demarcates an identifier.
@Document("Employee")
public class Employee {
@Id
private String empId;
private String name;
private int age;
private double salary;
//getters and setters
Spring Data MongoRepository Implementation
Spring Data includes repository support for MongoDB and the queries are constructed automatically, based on method names similar to JPARepository. The below implementation also shows an example to execute custom query in a MongoRepository using @Query
annotation. We have used this query to find department of an employee by an employee name.
@Repository public interface DepartmentRepository extends MongoRepository{ @Query(value = "{'employees.name': ?0}", fields = "{'employees' : 0}") Department findDepartmentByEmployeeName(String empName); List findDepartmentByName(String name); }
Using fields
, we can tell the driver about the fields that we are intrested in the result set.
Spring Boot MongoDB API implementation
Now, let us define our API implementation in a spring controller class that performs the CRUD operation. It will make use of predefined method names in MongoRepository to perform these operations. While implementing our Mongotemplate, we will be defining these implementation again with Query interface.
Create Operation
Create operation is a POST request and takes Department model object as a parameter and uses repository pre-defined save()
method to persist it to Mongo DB. It returns the saved instance and hence it will have the unique id in it.
@PostMapping public Department createDept(@RequestBody Department department) { departmentRepository.save(department); return department; }
Below is the equivalent implementation using MongoTemplate for Create operation.
public Department save(Department department) { mongoTemplate.save(department); return department; }
Read Operation
Read operation is a GET request and uses findAll()
defined in MongoRepository that returns all the documents of a collection.
@GetMapping public ListlistDepts(){ return departmentRepository.findAll(); }
Below is the equivalent implementation using MongoTemplate for Read operation.
public ListfindAll() { return mongoTemplate.findAll(Department.class); }
Update Operation
Update operation uses PUT request and accepts deptId as a path variable and calls the same save()
. In this case, since the id is present in the model object, it will get updated in the DB.
@PutMapping("/{deptId}") public Department updateDept(@RequestBody Department department, @PathVariable String deptId) { department.setId(deptId); departmentRepository.save(department); return department; }
Below is the equivalent implementation using MongoTemplate for update operation.
public Department update(Department department){ Query query = new Query(); query.addCriteria(Criteria.where("id").is(department.getId())); Update update = new Update(); update.set("name", department.getName()); update.set("description", department.getDescription()); return mongoTemplate.findAndModify(query, update, Department.class); }
Delete Operation
Delete operation uses delete request. Below is the controller implementation.
@DeleteMapping("/{deptId}") public String deleteDept(@PathVariable String deptId) { departmentRepository.deleteById(deptId); return deptId; }
Below is the equivalent implementation using MongoTemplate for delete operation.
public void deleteById(String deptId) { Query query = new Query(); query.addCriteria(Criteria.where("id").is(deptId)); mongoTemplate.remove(query, Department.class); }
Get Operation to Fetch Department By Name
It lists all the departments by name and show cases the usage of MongoRepository to query by attribute name of a model class.
@GetMapping("/{deptName}") public ListfindDeptByName(@PathVariable String deptName) { return departmentRepository.findDepartmentByName(deptName); }
Below is the equivalent implementation using MongoTemplate.
public ListfindDepartmentByName(String deptName){ Query query = new Query(); query.addCriteria(Criteria.where("name").is(deptName)); return mongoTemplate.find(query, Department.class); }
Embedded Elements Operations
It fetches parent elements by an attribute of child element. This basically shows ways to query for embedded elements in MongoDB. As implemented above, this specific implementation executes custom query in our DepartmentRepository.java
@GetMapping("{name}/emp") public Department listDept(@PathVariable String name){ return departmentRepository.findDepartmentByEmployeeName(name); }DeptRepository.java
@Repository public class DeptRepository { @Autowired private MongoTemplate mongoTemplate; public ListfindAll() { return mongoTemplate.findAll(Department.class); } public Department save(Department department) { mongoTemplate.save(department); return department; } public Department update(Department department){ Query query = new Query(); query.addCriteria(Criteria.where("id").is(department.getId())); Update update = new Update(); update.set("name", department.getName()); update.set("description", department.getDescription()); return mongoTemplate.findAndModify(query, update, Department.class); } public List findDepartmentByName(String deptName){ Query query = new Query(); query.addCriteria(Criteria.where("name").is(deptName)); return mongoTemplate.find(query, Department.class); } public void deleteById(String deptId) { Query query = new Query(); query.addCriteria(Criteria.where("id").is(deptId)); mongoTemplate.remove(query, Department.class); } }
Testing Spring Boot MongoDB App
Now, our implementation is ready for testing. Let us start our SpringBootMongoApplication.java as a java application and hit our endpoints.
Create Operation Test
POST Request Payload{ "name":"Devglan", "description": "devglan", "employees":[ { "empId":"CET02", "age":23, "salary":542452 } ] }
Fetch Department By Emp Name
Conclusion
In this tutorial, we learnt about creating a spring boot app with MongoDB and exposed some REST endpoints for different CRUD operations. We integrated MongoRepository and MongoTemplate too. To add security in this application, you can follow this article.