Using MongoDB in a Spring Boot application

Marcos
5 min readMar 12, 2023

What we will do in this text?

  • Run MongoDB using docker;
  • Create a CRUD API using Spring Boot and MongoDB;

Now, let’s run MongoDB using Docker

Create a docker-compose.yml file:

version: '3.1'
services:
mongo:
image: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: example

Run with this command:

docker-compose up

Using MongoDB Compass

If you don’t have this installed, it’s a good time to install it.

Use this string connection: mongodb://root:example@localhost:27017/ to connect.

After, create a database and a collection:

Importing data

Here https://www.kaggle.com/datasets we can get a database to import and use in our study environment.

I will choose this database https://www.kaggle.com/datasets/deepcontractor/marvel-comic-books

Download it.

Now, import the file:

It’s done:

The documents are available:

Now, let’s make some code

At first, we need these two dependencies:

  <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

Now, I mapped the documents in a java class:

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

@Document("rice_production")
public class RiceProductionData {

@Id
private String id;
@Field("Area")
private String area;
@Field("Year")
private String year;
@Field("Unit")
private String unit;
@Field("Value")
private String value;
@Field("Flag")
private String flag;
@Field("Flag Description")
private String flagDescription;

public RiceProductionData(String area, String year, String unit, String value, String flag, String flagDescription) {
this.area = area;
this.year = year;
this.unit = unit;
this.value = value;
this.flag = flag;
this.flagDescription = flagDescription;
}

public static RiceProductionData update(final String id, final RiceProductionData riceProductionData) {
final RiceProductionData riceProductionDataUpdated = new RiceProductionData();
riceProductionDataUpdated.setId(id);
riceProductionDataUpdated.setArea(riceProductionData.getArea() == null? null : riceProductionData.getArea());
riceProductionDataUpdated.setFlag(riceProductionData.getFlag() == null? null : riceProductionData.getFlag());
riceProductionDataUpdated.setYear(riceProductionData.getYear() == null? null : riceProductionData.getYear());
riceProductionDataUpdated.setUnit(riceProductionData.getUnit() == null? null : riceProductionData.getUnit());
riceProductionDataUpdated.setValue(riceProductionData.getValue() == null? null : riceProductionData.getValue());
riceProductionDataUpdated.setFlagDescription(riceProductionData.getFlagDescription() == null? null : riceProductionData.getFlagDescription());
return riceProductionDataUpdated;
}

public String getId() {
return id;
}

public String getArea() {
return area;
}

public String getYear() {
return year;
}

public String getUnit() {
return unit;
}

public String getValue() {
return value;
}

public String getFlag() {
return flag;
}

public String getFlagDescription() {
return flagDescription;
}
}

The method called “update” will auxiliary in an update.

And then created a repository interface:

import com.example.demo.adapters.database.document.RiceProductionData;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repository
public interface SpringDataRiceProductionRepository extends MongoRepository<RiceProductionData, UUID> {
List<RiceProductionData> findByArea(final String countryName);
}

The method findByArea is an example of using a property to filter.

And put the annotation @EnableMongoRepositories in the main class:

import com.example.demo.adapters.database.repository.SpringDataRiceProductionRepository;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

@EnableMongoRepositories(basePackageClasses = SpringDataRiceProductionRepository.class)
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

Now, I will create a controller class:

import com.example.demo.adapters.database.document.RiceProductionData;
import com.example.demo.adapters.database.repository.SpringDataRiceProductionRepository;
import org.springframework.data.domain.Example;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/rice-production")
public class RiceProductionController {

private final SpringDataRiceProductionRepository springDataRiceProductionRepository;

public RiceProductionController(final SpringDataRiceProductionRepository springDataRiceProductionRepository) {
this.springDataRiceProductionRepository = springDataRiceProductionRepository;
}

@PostMapping
public ResponseEntity<?> create(@RequestBody final RiceProductionData riceProductionData) {
return ResponseEntity.ok(springDataRiceProductionRepository.save(riceProductionData));
}

@PutMapping("/{id}")
public ResponseEntity<?> update(@PathVariable final String id, @RequestBody final RiceProductionData riceProductionData) {
var response = springDataRiceProductionRepository.findById(id);
if(response.isEmpty()) {
return ResponseEntity.notFound().build();
}
var responseUpdated = RiceProductionData.update(id, riceProductionData);
return ResponseEntity.ok(springDataRiceProductionRepository.save(responseUpdated));
}

@GetMapping
public ResponseEntity<?> listRiceproduction() {
return ResponseEntity.ok(springDataRiceProductionRepository.findAll());
}

@GetMapping("/area/{countryName}")
public ResponseEntity<?> findByArea(@PathVariable final String countryName) {
return ResponseEntity.ok(springDataRiceProductionRepository.findByArea(countryName));
}

@GetMapping("/{id}")
public ResponseEntity<?> findById(@PathVariable final String id) {
return ResponseEntity.ok(springDataRiceProductionRepository.findById(id));
}

@DeleteMapping("/{id}")
public ResponseEntity<?> deleteById(@PathVariable final String id) {
springDataRiceProductionRepository.deleteById(id);
return ResponseEntity.ok().build();
}
}

You are thinking why there is a repository here, huh? Relax, it’s only a test.

Tests

We will execute some curls:

POST

curl --location --request POST 'http://localhost:8080/rice-production' \
--header 'Content-Type: application/json' \
--data-raw '{
"area": "Brazil",
"year": "1900",
"unit": "tonnes",
"value": "50000",
"flag": "A",
"flagDescription": "Official figure"
}'

Response:

{
"id": "640e0cc1ee5b2a06c23630df",
"area": "Brazil",
"year": "1900",
"unit": "tonnes",
"value": "50000",
"flag": "A",
"flagDescription": "Official figure"
}

GET by area (or country)

curl --location --request GET 'http://localhost:8080/rice-production/area/Brazil'

Response:

[
{
"id": "640df82a6a39a9848c47feda",
"area": "Brazil",
"year": "1961",
"unit": "tonnes",
"value": "5392477",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fedb",
"area": "Brazil",
"year": "1962",
"unit": "tonnes",
"value": "5556834",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fedc",
"area": "Brazil",
"year": "1963",
"unit": "tonnes",
"value": "5740065",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fedd",
"area": "Brazil",
"year": "1964",
"unit": "tonnes",
"value": "6344931",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fede",
"area": "Brazil",
"year": "1965",
"unit": "tonnes",
"value": "7579649",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fedf",
"area": "Brazil",
"year": "1966",
"unit": "tonnes",
"value": "5801814",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fee0",
"area": "Brazil",
"year": "1967",
"unit": "tonnes",
"value": "6791990",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fee1",
"area": "Brazil",
"year": "1968",
"unit": "tonnes",
"value": "6652388",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fee2",
"area": "Brazil",
"year": "1969",
"unit": "tonnes",
"value": "6394285",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fee3",
"area": "Brazil",
"year": "1970",
"unit": "tonnes",
"value": "7553083",
"flag": "A",
"flagDescription": "Official figure"
},
{
"id": "640df82a6a39a9848c47fee4",
"area": "Brazil",
"year": "1971",
"unit": "tonnes",
"value": "6593179",
"flag": "A",
"flagDescription": "Official figure"
},
//...
{
"id": "640df82a6a39a9848c47ff16",
"area": "Brazil",
"year": "2021",
"unit": "tonnes",
"value": "11660603",
"flag": "A",
"flagDescription": "Official figure"
}
]

GET by id

curl --location --request GET 'http://localhost:8080/rice-production/640df82a6a39a9848c47feda'

Response:

{
"id": "640df82a6a39a9848c47feda",
"area": "Brazil",
"year": "1961",
"unit": "tonnes",
"value": "5392477",
"flag": "A",
"flagDescription": "Official figure"
}

DELETE by id

curl --location --request DELETE 'http://localhost:8080/rice-production/640df82a6a39a9848c47feda'

PUT

First, I choose a document:

{
"id": "640df82a6a39a9848c47fedc",
"area": "Brazil",
"year": "1963",
"unit": "tonnes",
"value": "5740065",
"flag": "A",
"flagDescription": "Official figure"
}

Then I made this curl changing the year to 1903:

curl --location --request PUT 'http://localhost:8080/rice-production/640df82a6a39a9848c47fedc' \
--header 'Content-Type: application/json' \
--data-raw '{
"area": "Brazil",
"year": "1903",
"unit": "tonnes",
"value": "5740065",
"flag": "A",
"flagDescription": "Official figure"
}'

And executing a GET by id again, the result is:

{
"id": "640df82a6a39a9848c47fedc",
"area": "Brazil",
"year": "1903",
"unit": "tonnes",
"value": "5740065",
"flag": "A",
"flagDescription": "Official figure"
}

So far so good until here, right?

This code is here: https://github.com/mmarcosab/springboot-mongo-demo

That’s it for today.

--

--