Spring Data Unlocked: Getting Started With Java and MongoDB
Ricardo Mello5 min read • Published Nov 08, 2024 • Updated Nov 11, 2024
FULL APPLICATION
Rate this tutorial
If you are a Java developer who is passionate about MongoDB and Spring, I have good news: You're in the right place.
This series of articles will explore how to integrate MongoDB with Spring Data in a very simple and easy way. The main idea is to have a vision of how to take the first step and, at the same time, evolve our knowledge by exploring the capabilities that Spring Data offers us. By the end of this series, you'll have a clear understanding of the differences between MongoRepository and MongoTemplate, know when to use each one, and be able to create complex queries while improving their performance by using indexes.
- Get started with MongoDB Atlas for free! If you don’t already have an account, MongoDB offers a free-forever Atlas cluster.
- IDE of your choice
Spring Data is a solution that simplifies data access in databases like MongoDB. Its main goal is to provide an easy and consistent approach to working with data while preserving the unique characteristics of MongoDB. And, of course, all of this is within the Spring ecosystem.
We can perform basic CRUD operations easily, and the framework can automatically create queries based on method names, reducing the amount of boilerplate code we need to write. Some key points:
- Repository support: Spring offers us a way to communicate with MongoDB at a high level of abstraction, providing very simple CRUD operations to use.
- Query derivation: We can create quick queries using the method signature, which is ideal for those who want agility.
- Mapping and serialization: Simplify the mapping and serialization of objects through annotations.
- Aggregation framework:** **Spring provides support for the aggregation framework through annotations and also through the aggregation class itself.
- Auto-index-Creation: We have the option to work with indexes managed by Spring itself (we will explore this in more detail in the second series of this article).
To explore the capabilities of Spring, we will define a data model where we will work with transactions between bank accounts. Our model will ultimately deliver a document like this:
1 { 2 "id": "672182814338f60133ee26e1", 3 "transactionType": "Debit", 4 "amount": 888.0, 5 "currency": "USD", 6 "status": "In Progress", 7 "description": "Transfer to Ricardo", 8 "createdAt": "2024-10-09T14:00:00", 9 "accountDetails": { 10 "originator": { 11 "accountNumber": "2376543213", 12 "name": "Maria", 13 "bank": "Bank G" 14 }, 15 "beneficiary": { 16 "accountNumber": "2234987651", 17 "name": "Ricardo Mello", 18 "bank": "Bank V" 19 } 20 } 21 }
As you can see, we have several types of fields and subdocuments, which will be very useful for exploring our queries.
- Project: Gradle - Kotlin
- Language: Java
- Spring Boot: The latest version
We'll also add the following dependencies:
- Lombok: This simplifies code by automatically generating boilerplate code, like getters and setters.
- Spring Web: We'll use this to create endpoints for our application.
After that, simply click on "Generate" and open the project in your favorite IDE (I'm using IntelliJ).
To connect to MongoDB using Spring, we'll use the
application.properties
file and define the following variables:1 spring.application.name=SpringShop 2 spring.data.mongodb.uri=<YOUR_CONNECTION_STRING> 3 spring.data.mongodb.database=springshop
Next, we will create our transaction class (based on our business model). To do this, simply create a class as follows:
1 package com.mongodb; 2 3 import lombok.Data; 4 import org.springframework.data.annotation.Id; 5 import org.springframework.data.mongodb.core.mapping.Document; 6 import java.time.LocalDateTime; 7 8 9 10 public class Transaction { 11 12 private String id; 13 private String transactionType; 14 private Double amount; 15 private String currency; 16 private String status; 17 private String description; 18 private LocalDateTime createdAt; 19 private AccountDetails accountDetails; 20 21 public record AccountDetails(Originator originator, Beneficiary beneficiary) {} 22 public record Originator(String accountNumber, String name, String bank) {} 23 public record Beneficiary(String accountNumber, String name, String bank) {} 24 }
The transaction class is quite simple and includes the information from our model. Here, we have three annotations that I would like to discuss:
- @Document: This indicates to Spring that this class is a MongoDB document.
- @Data: This is a Lombok annotation that generates boilerplate code such as getters, setters, toString, equals, and hashCode methods.
- @Id: This will automatically generate an
_id
(ObjectId) for us.
Before we move on to communication with MongoDB, we need to talk about the level of abstraction. MongoTemplate and MongoRepository are both part of Spring Data and offer different levels of abstraction for interacting with MongoDB.
While MongoRepository is designed for those who want faster development, MongoTemplate is better suited for those who need more flexibility.
Alright, now that we can differentiate between them, we can choose one (or both) to work with.
Now, it's time to create our class that will handle communication with MongoDB. In this first part, we'll focus on simplicity and efficiency and use the
MongoRepository
interface provided by Spring. To do this, create a class called TransactionRepository
as shown below:1 package com.mongodb; 2 3 import org.springframework.data.mongodb.repository.MongoRepository; 4 import org.springframework.stereotype.Repository; 5 6 7 public interface TransactionRepository extends MongoRepository <Transaction, String>{}
In this example, we're extending the
MongoRepository
interface, which allows us to inherit several powerful features provided by Spring Data that we can apply to our Transaction
entity.Let's take advantage of the high level of abstraction provided by MongoRepository and create two methods for insertion and querying. To do this, we will create a TransactionService class:
1 package com.mongodb; 2 import org.springframework.stereotype.Service; 3 import java.util.List; 4 5 6 public class TransactionService { 7 private final TransactionRepository transactionRepository; 8 9 public TransactionService(TransactionRepository transactionRepository) { 10 this.transactionRepository = transactionRepository; 11 } 12 List<Transaction> getTransactions() { 13 return transactionRepository.findAll(); 14 } 15 public Transaction save(Transaction transaction) { 16 return transactionRepository.save(transaction); 17 } 18 }
Now, to finish this first part of our series, we will create our controller to test the insert and find operations. To do this, simply execute the following code:
1 package com.mongodb; 2 3 import org.springframework.http.HttpStatus; 4 import org.springframework.http.ResponseEntity; 5 import org.springframework.web.bind.annotation.*; 6 7 import java.util.List; 8 9 10 11 public class TransactionController { 12 13 private final TransactionService transactionService; 14 15 public TransactionController(TransactionService transactionService, TransactionRepository transactionRepository) { 16 this.transactionService = transactionService; 17 } 18 19 20 public List<Transaction> getTransactions() { 21 return transactionService.getTransactions(); 22 } 23 24 25 public ResponseEntity<Transaction> create( Transaction transaction) { 26 return ResponseEntity.status(HttpStatus.CREATED).body(transactionService.save(transaction)); 27 } 28 }
Notice: We could create some classes to better handle our traffic
objects. However, we will focus on simplicity for now.
If you haven't run the application yet, remember to update the connection string to your database. With the application running, let's insert a document using the following cURL command:
1 curl --location 'http://localhost:8080/transactions' \ 2 --header 'Content-Type: application/json' \ 3 --data '{ 4 "transactionType": "Transfer", 5 "amount": 1500.5, 6 "currency": "USD", 7 "status": "Completed", 8 "description": "Transfer to Ricardo", 9 "createdAt": "2024-10-09T14:00:00.000Z", 10 "accountDetails": { 11 "originator": { 12 "accountNumber": "9876543210", 13 "name": "Maria Faria", 14 "bank": "Bank A" 15 }, 16 "beneficiary": { 17 "accountNumber": "1234987654", 18 "name": "Ricardo Mello", 19 "bank": "Bank B" 20 } 21 } 22 }'
If everything goes well, we can query our records using the
findAll
method:1 curl --location 'http://localhost:8080/transactions'
I'm using Postman to perform the cURL requests and see the results.
As you can see, our inserted document matches the model we defined initially.
In this first part of the Spring Data Unlocked series, we learned how to get started with Spring Data and MongoDB. The article demonstrates how to create a project from scratch and integrate it in a simple and straightforward way. We modeled our entity that will be used in the upcoming articles, where we will explore the capabilities of Spring with aggregations and more complex queries. To continue reading, check out the second part: Advanced Queries With MongoDB.
If you have any questions, feel free to leave them in the comments.
The complete code is available in mongo-developer GitHub.
Top Comments in Forums
There are no comments on this article yet.