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 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.
1 2 3 4 5 6 7 |
<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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
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.
- 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. - 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.
- 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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.
1 2 3 4 5 6 7 8 9 10 11 |
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.
- Spring Data MongoDB provides wrapper over the MongoDB java driver, internally it’s using MongoDB java driver to perform database operations.
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 requiresMongo
orMongoClient
(for newer MongoDB java driver versions) orMongoDbFactory
to initialize it. We also need to provide the database name which will be used.- If database is password protected, we can use
org.springframework.data.authentication.UserCredentials
to pass the authentication username and password details. org.springframework.data.mongodb.core.query.Query
andorg.springframework.data.mongodb.core.query.Criteria
classes are used to define the query used to find particular record or records.- 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<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>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
1 2 3 4 5 6 7 8 9 10 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:context="https://www.springframework.org/schema/context" xmlns:mongo="https://www.springframework.org/schema/data/mongo" xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.0.xsd https://www.springframework.org/schema/data/mongo https://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,
1 2 3 4 5 6 |
<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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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.
1 2 3 4 5 6 7 8 9 10 11 |
<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.