Spring Data MongoDB Example

Filed Under: MongoDB

Welcome to Spring Data MongoDB example. Spring Data MongoDB is one of the Spring projects for integrating Spring Framework with most widely used NoSQL database MongoDB.

Spring Data MongoDB

One of the key benefit of using Spring is that it provides integration with most of the major frameworks that are used in enterprise application. For example, Spring ORM Hibernate Integration.

We will use latest version of Spring Framework and Spring Data MongoDB for our example project. Our final Spring Data MongoDB example project will look like below image.

Spring Data MongoDB, Spring Data MongoDB Example, Spring MongoDB

Spring Data MongoDB can be used in a simple application too, it’s not required to use Spring framework with it. Let’s see this with a simple Spring MongoDB example. For that all you need to include below dependencies in pom.xml file, it will automatically include the compatible MongoDB java driver through maven transitive dependencies.


<dependency>
	<groupId>org.springframework.data</groupId>
	<artifactId>spring-data-mongodb</artifactId>
	<version>1.5.2.RELEASE</version>
</dependency>

Spring Data MongoDB Example – Model Bean

We will have a simple model bean with some variables to be stored in MongoDB database.

Person.java


package com.journaldev.spring.mongodb.model;

import org.springframework.data.annotation.Id;

public class Person {

	//id will be used for storing MongoDB _id
	@Id
	private String id;
	
	private String name;
	private String address;
	
	public Person(){}
	public Person(String i, String n, String a){
		this.id=i;
		this.name=n;
		this.address=a;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	
	@Override
	public String toString(){
		return id+"::"+name+"::"+address;
	}
}

It’s a simple java bean, however there are few important points that you should know.

  1. We know that every document in MongoDB is required to have a primary key with name _id, we can either provide it or MongoDB will generate it for us. We can use org.springframework.data.annotation.Id annotation with a model bean variable to map it to _id field.
  2. If the field name is “id” then we don’t need to use the @Id annotation, however it’s best practice to use it. In above class, we could have skipped @Id annotation.
  3. You should always have id field in the bean, otherwise it will not be mapped to any of the properties of the object and you will loose the primary key reference.

Now let’s see how we can easily use Spring Data MongoDB to perform CRUD operations on MongoDB database.

SpringDataMongoDBMain.java


package com.journaldev.spring.mongodb.main;

import java.net.UnknownHostException;

import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import com.journaldev.spring.mongodb.model.Person;
import com.mongodb.MongoClient;

public class SpringDataMongoDBMain {

	public static final String DB_NAME = "journaldev";
	public static final String PERSON_COLLECTION = "Person";
	public static final String MONGO_HOST = "localhost";
	public static final int MONGO_PORT = 27017;

	public static void main(String[] args) {
		try {
			MongoClient mongo = new MongoClient(
					MONGO_HOST, MONGO_PORT);
			MongoOperations mongoOps = new MongoTemplate(mongo, DB_NAME);
			Person p = new Person("113", "PankajKr", "Bangalore, India");
			mongoOps.insert(p, PERSON_COLLECTION);

			Person p1 = mongoOps.findOne(
					new Query(Criteria.where("name").is("PankajKr")),
					Person.class, PERSON_COLLECTION);

			System.out.println(p1);
			
			mongoOps.dropCollection(PERSON_COLLECTION);
			mongo.close();
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
	}

}

Now when I run above Spring Data MongoDB example program, it generates following output.


02:02:14.785 [main] DEBUG o.s.d.m.c.i.MongoPersistentEntityIndexCreator - Analyzing class class com.journaldev.spring.mongodb.model.Person for index information.
02:02:14.794 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - Inserting DBObject containing fields: [_class, _id, name, address] in collection: Person
02:02:14.798 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[journaldev]
02:02:14.824 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - findOne using query: { "name" : "PankajKr"} fields: null for class: class com.journaldev.spring.mongodb.model.Person in collection: Person
02:02:14.826 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[journaldev]
02:02:14.826 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - findOne using query: { "name" : "PankajKr"} in db.collection: journaldev.Person
113::PankajKr::Bangalore, India
02:02:14.833 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[journaldev]
02:02:14.835 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - Dropped collection [journaldev.Person]

We can conclude following points for Spring Data MongoDB from our learning till now.

  1. Spring Data MongoDB provides wrapper over the MongoDB java driver, internally it’s using MongoDB java driver to perform database operations.
  2. MongoOperations declares a lot of methods for different operations and most of the time, they are sufficient for us. MongoTemplate is the implementation class and it requires Mongo or MongoClient (for newer MongoDB java driver versions) or MongoDbFactory to initialize it. We also need to provide the database name which will be used.
  3. If database is password protected, we can use org.springframework.data.authentication.UserCredentials to pass the authentication username and password details.
  4. org.springframework.data.mongodb.core.query.Query and org.springframework.data.mongodb.core.query.Criteria classes are used to define the query used to find particular record or records.
  5. The major benefit of Spring Data MongoDB is that we don’t need to worry about the conversion of java bean to Mongo DBObject and vice versa, as we saw in MongoDB Java Example.

Now let’s move forward to use Spring Data MongoDB in Spring environment. It’s very simple and mostly requires configuration related code that we can do through XML, annotations or through java config. However I will use XML based configuration for Spring Data MongoDB example.

Here is my final pom.xml with Spring Framework and Spring Data MongoDB dependencies.


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.samples</groupId>
  <artifactId>SpringMongo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Spring -->
		<spring-framework.version>4.0.3.RELEASE</spring-framework.version>
		<spring-data-mongodb.version>1.5.2.RELEASE</spring-data-mongodb.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

	</properties>
	
	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		
		<dependency>
    		<groupId>org.springframework.data</groupId>
    		<artifactId>spring-data-mongodb</artifactId>
    		<version>${spring-data-mongodb.version}</version>
  		</dependency>
  
		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

	</dependencies>	
</project>

Spring Data MongoDB DAO Classes

We will use DAO pattern for exposing different operations that can be performed on Person object.

PersonDAO.java


package com.journaldev.spring.mongodb.dao;

import com.journaldev.spring.mongodb.model.Person;

public interface PersonDAO {

	public void create(Person p);
	
	public Person readById(String id);
	
	public void update(Person p);
	
	public int deleteById(String id);
}

Below is the MongoDB specific implementation class.

PersonDAOImpl.java


package com.journaldev.spring.mongodb.dao;

import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import com.journaldev.spring.mongodb.model.Person;
import com.mongodb.WriteResult;

public class PersonDAOImpl implements PersonDAO {

	private MongoOperations mongoOps;
	private static final String PERSON_COLLECTION = "Person";
	
	public PersonDAOImpl(MongoOperations mongoOps){
		this.mongoOps=mongoOps;
	}
	
	@Override
	public void create(Person p) {
		this.mongoOps.insert(p, PERSON_COLLECTION);
	}

	@Override
	public Person readById(String id) {
		Query query = new Query(Criteria.where("_id").is(id));
		return this.mongoOps.findOne(query, Person.class, PERSON_COLLECTION);
	}

	@Override
	public void update(Person p) {
		this.mongoOps.save(p, PERSON_COLLECTION);
	}

	@Override
	public int deleteById(String id) {
		Query query = new Query(Criteria.where("_id").is(id));
		WriteResult result = this.mongoOps.remove(query, Person.class, PERSON_COLLECTION);
		return result.getN();
	}

}

The code is pretty straight forward, so I won’t explain about them in detail.

Spring Data MongoDB Bean Configuration File

As always, the most important part of this application will be the spring bean configuration file. We will inject dependencies into different beans and define them.

Here is our final spring bean configuration file.

spring.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mongo="http://www.springframework.org/schema/data/mongo"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
		http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.5.xsd">

<mongo:mongo host="localhost" port="27017" id="mongo" />
<mongo:db-factory dbname="journaldev" mongo-ref="mongo" id="mongoDbFactory" />

<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
	<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
</bean>

<bean id="personDAO" class="com.journaldev.spring.mongodb.dao.PersonDAOImpl">
	<constructor-arg name="mongoOps" ref="mongoTemplate"/>
</bean>
</beans>

The important configurations that should be present are – Spring Data MongoDB schema and Mongo instance for MongoDB connection. I have defined MongoDbFactory instance for my convenience, we could also define MongoTemplate bean like below,


<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
	<constructor-arg name="mongo" ref="mongo" />
	<constructor-arg name="databaseName" value="journaldev" />
</bean>

Spring Data MongoDB Test Program

Finally, let’s write a simple test program and run some CRUD operations on MongoDB database.

SpringMongoDBXMLMain.java


package com.journaldev.spring.mongodb.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.spring.mongodb.dao.PersonDAO;
import com.journaldev.spring.mongodb.model.Person;

public class SpringMongoDBXMLMain {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
		
		PersonDAO personDAO = ctx.getBean("personDAO", PersonDAO.class);
		
		Person p = new Person(null, "PankajKr", "Bangalore, India");
		
		//create
		personDAO.create(p);
		System.out.println("Generated ID="+p.getId());
		
		//read
		Person p1 = personDAO.readById(p.getId());
		System.out.println("Retrieved Person="+p1);
		
		//update
		p1.setName("David");p1.setAddress("SFO, USA");
		personDAO.update(p1);
		Person temp = personDAO.readById(p1.getId());
		System.out.println("Retrieved Person after update="+temp);
		
		//delete
		int count = personDAO.deleteById(p1.getId());
		System.out.println("Number of records deleted="+count);
		
		ctx.close();

	}

}

Now when I run above application, it generates following output.


02:27:34.509 [main] DEBUG o.s.d.m.c.i.MongoPersistentEntityIndexCreator - Analyzing class class com.journaldev.spring.mongodb.model.Person for index information.
02:27:34.516 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - Inserting DBObject containing fields: [_class, _id, name, address] in collection: Person
02:27:34.520 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[journaldev]
Generated ID=53f50bbe0364b65dbc0c4753
02:27:34.532 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - findOne using query: { "_id" : "53f50bbe0364b65dbc0c4753"} fields: null for class: class com.journaldev.spring.mongodb.model.Person in collection: Person
02:27:34.533 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[journaldev]
02:27:34.535 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - findOne using query: { "_id" : { "$oid" : "53f50bbe0364b65dbc0c4753"}} in db.collection: journaldev.Person
Retrieved Person=53f50bbe0364b65dbc0c4753::PankajKr::Bangalore, India
02:27:34.543 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - Saving DBObject containing fields: [_class, _id, name, address]
02:27:34.543 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[journaldev]
02:27:34.545 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - findOne using query: { "_id" : "53f50bbe0364b65dbc0c4753"} fields: null for class: class com.journaldev.spring.mongodb.model.Person in collection: Person
02:27:34.545 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[journaldev]
02:27:34.546 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - findOne using query: { "_id" : { "$oid" : "53f50bbe0364b65dbc0c4753"}} in db.collection: journaldev.Person
Retrieved Person after update=53f50bbe0364b65dbc0c4753::David::SFO, USA
02:27:34.549 [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[journaldev]
02:27:34.550 [main] DEBUG o.s.data.mongodb.core.MongoTemplate - Remove using query: { "_id" : { "$oid" : "53f50bbe0364b65dbc0c4753"}} in collection: Person.
Number of records deleted=1
02:27:34.553 [main] INFO  o.s.c.s.ClassPathXmlApplicationContext - Closing org.springframework.context.support.ClassPathXmlApplicationContext@7a187814: startup date [Thu Aug 21 02:27:33 GMT+05:30 2014]; root of context hierarchy
02:27:34.553 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
02:27:34.553 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3f64b09c: defining beans [mongo,org.springframework.beans.factory.config.CustomEditorConfigurer#0,org.springframework.beans.factory.config.CustomEditorConfigurer#1,org.springframework.beans.factory.config.CustomEditorConfigurer#2,mongoDbFactory,mongoTemplate,personDAO]; root of factory hierarchy
02:27:34.554 [main] DEBUG o.s.b.f.s.DisposableBeanAdapter - Invoking destroy() on bean with name 'mongoDbFactory'
02:27:34.554 [main] DEBUG o.s.b.f.s.DisposableBeanAdapter - Invoking destroy() on bean with name 'mongo'

Notice that when Spring context is closed, it’s taking care of closing the MongoDB connections too, so we don’t need to worry about that.

Also I am providing MongoDB Collection name in each of the queries, we can skip that if the collection name confirms to java naming convention. For example, for “Person” and “PersonAddress” objects default collection name used by Spring MongoDB would be “person” and “personAddress” respectively.

We can also use org.springframework.data.mongodb.core.mapping.Document annotation with Model class to define the collection name to be used for saving the document.

Spring Data MongoDB Annotation Based Configuration

If you want to use annotation based configuration, below Configuration class can be used for reference.

SpringMongoDBConfiguration.java


package com.journaldev.spring.mongodb.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
 
import com.mongodb.MongoClient;
 
@Configuration
public class SpringMongoDBConfiguration {
 
	public @Bean MongoDbFactory getMongoDbFactory() throws Exception {
		return new SimpleMongoDbFactory(new MongoClient("localhost",27017), "journaldev");
	}

	public @Bean MongoTemplate getMongoTemplate() throws Exception {
		MongoTemplate mongoTemplate = new MongoTemplate(getMongoDbFactory());
		return mongoTemplate;
	}
}

We would need other configurations too to inject MongoTemplate bean into our DAO implementation class, I am leaving that part to you.

Using MongoOptions for MongoDB Connection Options

We can use MongoOptions to define MongoDB options in spring bean configuration file like below. There are some other configuration options too, that you can check for optimizing your connections.


<mongo:mongo host="localhost" port="27017">
    <mongo:options connections-per-host="4"
                   connect-timeout="1000"
                   max-wait-time="1500"
                   auto-connect-retry="true"
                   socket-keep-alive="true"
                   socket-timeout="1500"
                   write-fsync="true" />
  </mongo:mongo>

Spring Data MongoDB Example Summary

I hope this tutorial was good enough to get you started with Spring Data MongoDB, it’s not feasible to cover everything. You should look more into Query, Criteria and MongoTemplate methods to learn more. You can download the final project from below link.

Comments

  1. Mahmmed says:

    how to fetch the above details in my java program?

  2. Savani says:

    Could you please developed code for the Mongo DB to XML Spring Batch example ?

  3. Balaji says:

    Good post. Thanks

  4. HARSH DUBEY says:

    When I will create the mongo database and trying to perform first CRUD operation, Do I need to create the table structure or mongodb will create it automatically.

  5. yogesh says:

    I am having some problem with both host & port because i am trying to connect with mongodb which is on remote server. I am gettin error as below :

    Unable to connect to any server that matches AnyServerSelector{}; nested exception is com.mongodb.MongoServerSelectionException: Unable to connect to any server that matches AnyServerSelector{}

    Could you please help me ?

  6. Vivek says:

    Good post ….thanks

  7. Chris says:

    I’m new to Spring Data and intend to use it in a future project. DB of choice will be MongoDB.

    I noticed that you define a ‘PERSON_COLLECTION’ and this is different than all other tutorials whereby they tell us that the collection will be determined by reflection, or an annotation may be used.

    I have a very specific need where my collections are ‘mapped’ to hashed names. A little lengthy to explain all the details, but one user could name his collection ‘MyCollection’ and it will be mapped to a 123456789 (random) collection on its creation. Another user could name his collection ‘MyCollection’ (also) and it will be mapped to 987654321 (again, random id). This allows for individual users to name their collections whatever they want but my underlying code maps it to something unique.

    So your example seems to suite my needs where a collection name can be provided real-time.

    All the other peoples examples of using reflection or annotation would not suite me.

    Can you confirm this? I hope I have explained myself well enough for you to understand.

    Thanks ahead of time.

    Chris

    1. Pankaj says:

      Yes, you can provide collection name real time as shown in the example program.

Leave a Reply

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

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages