Tutorial

Spring Boot MongoDB

Published on August 3, 2022
Default avatar

By Shubham

Spring Boot MongoDB

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Welcome to Spring Boot MongoDB example. Spring Boot is the easiest way to spin a spring project quickly and MongoDB is the most popular NoSQL database. Let’s see how to integrate spring with MongoDB database.

Spring Boot MongoDB

We need following APIs to work with Spring Boot and MongoDB database.

  • Spring Data MongoDB
  • Spring Boot

There are two approaches through which we can connect to MongoDB database - MongoRepository and MongoTemplate. We will try to establish what one API offers over another and when should you choose any one of them for your use-case. We will make use of Spring Initializr tool for quickly setting up the project. So, let’s get started.

Spring Boot MongoDB Project Setup

We will make use of Spring Initializr tool for quickly setting up the project. We will use just two dependencies as shown below: spring boot mongodb project setup using spring initializr Download the project and unzip it. Then import it into your favorite IDE - Eclipse or IntelliJ IDEA.

Maven Dependencies

Though we already completed the setup with the tool, if you want to set it up manually, we use Maven build system for this project and here are the dependencies we used:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.journaldev.spring</groupId>
	<artifactId>spring-boot-mongodb</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>spring-boot-mongodb</name>
	<description>Spring Boot MongoDB Example</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<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>

		<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>

Make sure to use stable version for Spring Boot from the maven central.

Spring Boot MongoDB Model Class

We have a simple model class User.java.

package com.journaldev.bootifulmongodb.model;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

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

@Document
public class User {

	@Id
	private String userId;
	private String name;
	private Date creationDate = new Date();
	private Map<String, String> userSettings = new HashMap<>();

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getCreationDate() {
		return creationDate;
	}

	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}

	public Map<String, String> getUserSettings() {
		return userSettings;
	}

	public void setUserSettings(Map<String, String> userSettings) {
		this.userSettings = userSettings;
	}
}

Spring Boot MongoDB APIs

We will have following functionalities and Database interactions in our app.

  • Get all users
  • Get a user with ID
  • Get user settings
  • Get a particular key from the Map
  • Add/Update user setting

Spring Data MongoDB - MongoRepository

Now we will use Spring Data MongoDB repository to access our data. Spring Data MongoRepository provide us common functionalities that we can easily plug-in and use it. Let us define our Repository interface.

package com.journaldev.bootifulmongodb.dal;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

import com.journaldev.bootifulmongodb.model.User;

@Repository
public interface UserRepository extends MongoRepository<User, String> {
}

Defining MongoDB properties

Before we lay out our controller, it is important that we make a connection with a local instance of MongoDB. We will use Spring Boot properties to do this.

#Local MongoDB config
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.username=root
spring.data.mongodb.password=root
spring.data.mongodb.database=user_db
spring.data.mongodb.port=27017
spring.data.mongodb.host=localhost

# App config
server.port=8102
spring.application.name=BootMongo
server.context-path=/user

So, the app will run on port 8102 and connect to a local mongoDB instance with provided credentials. If you have a local instance without authorization enabled, you can just remove the first three lines of configuration.

Defining the Spring Controller

Let us finally move to making our Controller class.

package com.journaldev.bootifulmongodb.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.journaldev.bootifulmongodb.dal.UserRepository;
import com.journaldev.bootifulmongodb.model.User;

@RestController
@RequestMapping(value = "/")
public class UserController {

	private final Logger LOG = LoggerFactory.getLogger(getClass());

	private final UserRepository userRepository;

	public UserController(UserRepository userRepository) {
		this.userRepository = userRepository;
	}
}

We just Autowired the repository interface dependency and we will use this next.

Defining the APIs

For the functionalities we mentioned, we will now be making APIs and accessing the userRepository dependency which will internally use Spring Data MongoRepository API. Notice that we do not have to write any database interaction code in the interface as Spring Data does it all for us.

Getting all users

@RequestMapping(value = "", method = RequestMethod.GET)
public List<User> getAllUsers() {
	LOG.info("Getting all users.");
	return userRepository.findAll();
}

findAll() is just a method which Spring Data MongoRepository provides internally.

Getting a user by ID

Now, let us get a specific user with an ID.

@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
public User getUser(@PathVariable String userId) {
	LOG.info("Getting user with ID: {}.", userId);
	return userRepository.findOne(userId);
}

findOne() is just a method which Spring Data MongoRepository provides internally to get an Object by an ID.

Adding a new User

We will be adding a new user in the function below.

@RequestMapping(value = "/create", method = RequestMethod.POST)
public User addNewUsers(@RequestBody User user) {
	LOG.info("Saving user.");
	return userRepository.save(user);
}

Getting User settings

Now that we have added sample data into the DB, let’s try to extract some part of it.

@RequestMapping(value = "/settings/{userId}", method = RequestMethod.GET)
public Object getAllUserSettings(@PathVariable String userId) {
	User user = userRepository.findOne(userId);
	if (user != null) {
		return user.getUserSettings();
	} else {
		return "User not found.";
	}
}

Getting a particular User setting

@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(@PathVariable String userId, @PathVariable String key) {
	User user = userRepository.findOne(userId);
	if (user != null) {
		return user.getUserSettings().get(key);
	} else {
		return "User not found.";
	}
}

Notice in the above query, we got the user object, then extracted the complete Setting map (which could have contained 1000s of objects) and finally got our own value. This is a downside for Spring Data query when we use it as straight API.

Adding a new User setting

Let’s try to add some data to an existing user:

@RequestMapping(value = "/settings/{userId}/{key}/{value}", method = RequestMethod.GET)
public String addUserSetting(@PathVariable String userId, @PathVariable String key, @PathVariable String value) {
	User user = userRepository.findOne(userId);
	if (user != null) {
		user.getUserSettings().put(key, value);
		userRepository.save(user);
		return "Key added";
	} else {
		return "User not found.";
	}
}

With all the code we wrote, it’s clear that we didn’t have to write a single line of code to access the database apart from defining the repository interface and autowiring the dependency. This is the ease Spring Data MongoRepository API offers us but it also has some downsides. We will elaborate this when we have defined the MongoTemplate version as well. Let’s get started with that too.

Spring Data MongoDB - MongoTemplate

We will be defining the MongoTemplate database queries here. With MongoTemplate, you will see that we have much more granular control over what we query and what data is included in the results.

Defining the DAL interface

To provide a contract at the database access layer, we will start by defining an interface which works just like our Spring Data in-built methods.

package com.journaldev.bootifulmongodb.dal;

import java.util.List;

import com.journaldev.bootifulmongodb.model.User;

public interface UserDAL {

	List<User> getAllUsers();

	User getUserById(String userId);

	User addNewUser(User user);

	Object getAllUserSettings(String userId);

	String getUserSetting(String userId, String key);

	String addUserSetting(String userId, String key, String value);
}

Implementing the DAL interface

Let’s move on and define these methods.

package com.journaldev.bootifulmongodb.dal;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;

import com.journaldev.bootifulmongodb.model.User;

@Repository
public class UserDALImpl implements UserDAL {

	@Autowired
	private MongoTemplate mongoTemplate;

	@Override
	public List<User> getAllUsers() {
		return mongoTemplate.findAll(User.class);
	}

	@Override
	public User getUserById(String userId) {
		Query query = new Query();
		query.addCriteria(Criteria.where("userId").is(userId));
		return mongoTemplate.findOne(query, User.class);
	}

	@Override
	public User addNewUser(User user) {
		mongoTemplate.save(user);
		// Now, user object will contain the ID as well
		return user;
	}

	@Override
	public Object getAllUserSettings(String userId) {
		Query query = new Query();
		query.addCriteria(Criteria.where("userId").is(userId));
		User user = mongoTemplate.findOne(query, User.class);
		return user != null ? user.getUserSettings() : "User not found.";
	}

	@Override
	public String getUserSetting(String userId, String key) {
		Query query = new Query();
		query.fields().include("userSettings");
		query.addCriteria(Criteria.where("userId").is(userId).andOperator(Criteria.where("userSettings." + key).exists(true)));
		User user = mongoTemplate.findOne(query, User.class);
		return user != null ? user.getUserSettings().get(key) : "Not found.";
	}

	@Override
	public String addUserSetting(String userId, String key, String value) {
		Query query = new Query();
		query.addCriteria(Criteria.where("userId").is(userId));
		User user = mongoTemplate.findOne(query, User.class);
		if (user != null) {
			user.getUserSettings().put(key, value);
			mongoTemplate.save(user);
			return "Key added.";
		} else {
			return "User not found.";
		}
	}
}

The method implementations in above class are using MongoTemplate dependency. See how getUserById(...) method gets the user. We construct a query and passed required parameters. What will interests you more is the getUserSetting query. Let us understand what happened above:

  • We constructed queries with criteria to check equality.
  • The include method includes the field names which the result should include when it is extracted from DB. This means, in this case, userSettings key will be extracted which will save a lot of data to be fetched which is not needed
  • Also, we queried upon both user and the map key. Id any of it isn’t found, we return empty data meaning the required key wasn’t found. This saves from even fetching the User object at all if the required key was not present

Spring Data MongoDB Test Run

We can run this app simply by using a single command:

mvn spring-boot:run

Once the app is running, we can try saving a new user by using this API:

https://localhost:8102/user/create

As this will be a POST request, we will be sending JSON data as well:

{
  "name" : "Shubham",
  "userSettings" : {
    "bike" : "pulsar"
  }
}

As we are returning the Mongo response itself, we will get something like:

{
  "userId": "5a5f28cc3178058b0fafe1dd",
  "name": "Shubham",
  "creationDate": 1516165830856,
  "userSettings": {
    "bike" : "pulsar"
  }
}

Spring Data MongoDB MongoRepository Example Create You can get all users by using the API as GET request:

https://localhost:8102/user/

We will get back something like:

[
  {
    "userId": "5a5f28cc3178058b0fafe1dd",
    "name": "Shubham",
    "creationDate": 1516165830856,
    "userSettings": {
      "bike" : "pulsar"
    }
  }
]

Spring Data MongoDB If you see above UserController class, we haven’t hooked up MongoTemplate to be used. Below code snippet shows the changes required to use MongoTemplate for reading user settings.

//define Data Access Layer object
private final UserDAL userDAL;

//initialize DAL object via constructor autowiring
public UserController(UserRepository userRepository, UserDAL userDAL) {
	this.userRepository = userRepository;
	this.userDAL = userDAL;
}

//change method implementation to use DAL and hence MongoTemplate
@RequestMapping(value = "/settings/{userId}", method = RequestMethod.GET)
public Object getAllUserSettings(@PathVariable String userId) {
    User user = userRepository.findOne(userId);
    if (user != null) {
        return userDAL.getAllUserSettings(userId);
    } else {
        return "User not found.";
    }
}

//change method implementation to use DAL and hence MongoTemplate
@RequestMapping(value = "/settings/{userId}/{key}", method = RequestMethod.GET)
public String getUserSetting(
        @PathVariable String userId, @PathVariable String key) {
    return userDAL.getUserSetting(userId, key);
}

Restart the app and run scenarios to get all user settings and to get any specific key. Below image shows the output from Postman app. Spring Data MongoDB MongoTemplate example Spring Data MongoDB MongoTemplate example criteria query

MongoTemplate vs MongoRepository

  • MongoTemplate provides a lot more control when it comes to querying data and what data to pull from database.
  • Spring Data repositories provide us a convenient outlook on how to fetch data.
  • MongoTemplate is database dependent. What this means is, with Spring Data repositories, you can easily switch to a different database altogether by simply using a different Spring Data repositories for MySQL or Neo4J or anything else. This is not possible with MongoTemplate.

Spring Boot MongoDB Summary

In this lesson, we looked at how MongoTemplate can provide us more control over Spring Data repositories but can also be a little complicated when deeper queries are involved. So, this is completely your call what to choose when you develop your idea. Feel free to leave comments below. Download the source code from below link. Please make sure that you change the MongoDB credentials before running the provided app.

Download Spring Boot MongoDB Example Project

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
Shubham

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
October 28, 2020

Nice Tutorials for learning MongoDB along with other Java based technology. As per above code, for adding the New User, Mapping methods should be Post, here it mentioned Get. Kindly rectify me, If I am wrong… ################################################ Adding a new User setting Let’s try to add some data to an existing user: @RequestMapping(value = “/settings/{userId}/{key}/{value}”, method = RequestMethod.GET) public String addUserSetting(@PathVariable String userId, @PathVariable String key, @PathVariable String value) { User user = userRepository.findOne(userId); if (user != null) { user.getUserSettings().put(key, value); userRepository.save(user); return “Key added”; } else { return “User not found.”; } }

- prashant sinha

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    August 20, 2020

    HOW TO CHECK MONGODB CONNECTION STATUS IN JAVA AND THROW CONNECTION ERROR

    - CHETAN

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      July 28, 2020

      Hi, little more info: A) DOCKER MONGODB: ==================== GIT DOCKER: https://hub.docker.com/\_/mongo PULL MONGO: docker pull mongo RUN DOCKER MONGO WITH NO USER+PSW: docker run -d --name mongo-on-docker-no-user-psw -p 27017:27017 mongo RUN DOCKER MONGO WITH USER+PSW: docker run -d --name mongo-on-docker-user-psw -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=secret mongo USER=mongoadmin + PSW=secret MONGODB CLENT APP MongoDB Compass (MongoDB 4.2.8 Community): ============================================================= https://www.mongodb.com/try/download/compass CONNECTIONS: MONGODB WITH NO USER+PSW: mongodb://localhost:27017/journaldev MONGODB WITH USER+PSW: mongodb://mongoadmin:secret@localhost:27017/journaldev

      - VLADIMIR

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        June 27, 2020

        I am getting below error when running the application. Can someone help! 20-06-27 22:44:46.903 INFO 9680 — [localhost:27017] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server localhost:27017 com.mongodb.MongoSocketOpenException: Exception opening socket at com.mongodb.connection.SocketStream.open(SocketStream.java:63) ~[mongodb-driver-core-3.4.3.jar:na] at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:115) ~[mongodb-driver-core-3.4.3.jar:na] at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:113) ~[mongodb-driver-core-3.4.3.jar:na] at java.base/java.lang.Thread.run(Unknown Source) [na:na] Caused by: java.net.ConnectException: Connection refused: connect at java.base/java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) ~[na:na] at java.base/java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source) ~[na:na] at java.base/java.net.AbstractPlainSocketImpl.doConnect(Unknown Source) ~[na:na] at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source) ~[na:na] at java.base/java.net.AbstractPlainSocketImpl.connect(Unknown Source) ~[na:na] at java.base/java.net.PlainSocketImpl.connect(Unknown Source) ~[na:na] at java.base/java.net.SocksSocketImpl.connect(Unknown Source) ~[na:na] at java.base/java.net.Socket.connect(Unknown Source) ~[na:na] at com.mongodb.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:57) ~[mongodb-driver-core-3.4.3.jar:na] at com.mongodb.connection.SocketStream.open(SocketStream.java:58) ~[mongodb-driver-core-3.4.3.jar:na] … 3 common frames omitted

        - Sharath Raj

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          March 12, 2020

          Thank you so much!

          - Anjali

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            January 18, 2020

            @EnableMongoRepositories is required in order to autowiring works.

            - Reza

              JournalDev
              DigitalOcean Employee
              DigitalOcean Employee badge
              January 7, 2020

              hello, does we need connector for that ?

              - joe

                JournalDev
                DigitalOcean Employee
                DigitalOcean Employee badge
                November 13, 2019

                where to put mongodb configs?

                - Shivam

                  JournalDev
                  DigitalOcean Employee
                  DigitalOcean Employee badge
                  October 9, 2019

                  I started learning integrating sprint boot with mongodb and just followed the same steps as given in the document and I also went through the comments to check out if I am missing anything, however when I hit GET API call I get this error Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName=‘root’, source=‘admin’, password=, mechanismProperties={}}; nested exception is com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName=‘root’, source=‘admin’, password=, mechanismProperties={}}", I am able to login to mongo shell and see the user is created here are my mongodb properties I have defined spring.data.mongodb.authentication-database=admin spring.data.mongodb.username=root spring.data.mongodb.password=root spring.data.mongodb.database=user_db spring.data.mongodb.port=27018 spring.data.mongodb.host=localhost authenticationMechanism=SCRAM-SHA-1 I also see below application logs com.mongodb.MongoCommandException: Command failed with error 18 (AuthenticationFailed): ‘Authentication failed.’ on server localhost:27018. The full response is { “ok” : 0.0, “errmsg” : “Authentication failed.”, “code” : 18, “codeName” : “AuthenticationFailed” } Can anyone help here?

                  - Yatheesh

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    July 24, 2019

                    Hi Sir , I am implement mongo very well and everything working fine but i have one question i want to run project spring boot with mongoDb but how to connection pooling like maximum-pool-size, max-lifetime, idle-timeout and if i am type wrong mongo password in application properties yet connect mongoDb how is possible . Please give the solution

                    - shivam awasthi

                      Try DigitalOcean for free

                      Click below to sign up and get $200 of credit to try our products over 60 days!

                      Sign up

                      Join the Tech Talk
                      Success! Thank you! Please check your email for further details.

                      Please complete your information!

                      Get our biweekly newsletter

                      Sign up for Infrastructure as a Newsletter.

                      Hollie's Hub for Good

                      Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

                      Become a contributor

                      Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

                      Welcome to the developer cloud

                      DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

                      Learn more
                      DigitalOcean Cloud Control Panel