Spring Data MongoDB Example
In this article, we will see a simple Java application demonstrating the CRUD operation (Create, retrieve, update and delete) using the MongoDB database and spring MongoDB module. MongoDB database is an open source document-oriented NoSQL database.
In our example, we will see how we can use MongoDB to persist, query, update and delete the documents.
1. MongoDB Setup
Let’s first setup MongoDB.
- Download MongoDB.
- Ensure you download the correct version of mongoDB. In my case it is MongoDB for windows 64-bit 2008 R2+
- Run the downloaded MSI installer file. You may chose the ‘Custom’ way, provide directory path where you want the downloaded files. We have installed mongoDB in
c:\mongoDB
. - Create a data directory to store the data files. We have created
data
folder within themongoDB
directory.C:\mongodb\bin>mongod.exe --dbpath "C:\mongodb\data"
- Start MongoDB
C:\mongodb\bin>mongod.exe --dbpath "C:\mongodb\data" 2015-12-28T20:14:41.731+0530 I CONTROL [main] Hotfix KB2731284 or later update is not installed, will zero-out data files 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] MongoDB starting : pid=6 932 port=27017 dbpath=C:\mongodb\data 64-bit host=INMAA1-L1005 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] targetMinOS: Windows 7/W indows Server 2008 R2 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] db version v3.2.0 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] git version: 45d947729a0 315accb6d4f15a6b06be6d9c19fe7 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] OpenSSL version: OpenSSL 1.0.1p-fips 9 Jul 2015 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] allocator: tcmalloc 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] modules: none 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] build environment: 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] distmod: 2008plus-ss l 2015-12-28T20:14:41.735+0530 I CONTROL [initandlisten] distarch: x86_64 2015-12-28T20:14:41.736+0530 I CONTROL [initandlisten] target_arch: x86_64 2015-12-28T20:14:41.736+0530 I CONTROL [initandlisten] options: { storage: { db Path: "C:\mongodb\data" } } 2015-12-28T20:14:41.789+0530 I STORAGE [initandlisten] wiredtiger_open config: create,cache_size=8G,session_max=20000,eviction=(threads_max=4),config_base=fals e,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snapp y),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),stati stics_log=(wait=0),direct_io=(data), 2015-12-28T20:14:41.900+0530 I NETWORK [HostnameCanonicalizationWorker] Startin g hostname canonicalization worker 2015-12-28T20:14:41.900+0530 I FTDC [initandlisten] Initializing full-time d iagnostic data capture with directory 'C:/mongodb/data/diagnostic.data' 2015-12-28T20:14:44.017+0530 I NETWORK [initandlisten] waiting for connections on port 27017
As you can see, MongoDB starts up and is now waiting for connections.
2. Maven Dependencies
Other than the spring context and beans, we also need spring-data-mongodb
to access spring MongoDB APIs.
pom.xml:
<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>com.javacodegeeks.camel</groupId> <artifactId>springQuartzScheduler</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>1.8.2.RELEASE</version> </dependency> </dependencies> </project>
3. Mongo JDBC Driver Example
Let’s first use MongoDB Java driver to perform the create/read/update/delete (CRUD) operations. After this we will try the same using spring MongoDB provided APIs.
In order to access MongoDB from Java we will first create an instance of Mongo
using MongoClient
. You should have one MongoClient instance for the entire JVM. Mongo
class abstracts the connection to a MongoDB instance.
If the MongoDB is not in your local machine then you need to pass in the machine address and port.
Mongo mongoClient = new MongoClient("localhost", 27017);
Calling getDb(database name)
on MongoDB instance returns us the the database object.
DB db = mongo.getDB("database");
Next thing we need to do is get the collection object.
DBCollection employee = db.getCollection("employees");
Once we have the collection object, we can insert documents into the collection. BasicDBObject
represents a MongoDB document.
DBObject employeeDetails = new BasicDBObject() .append("name", "Joe") .append("age", 41) .append("company", new BasicDBObject().append("name", "ABC"));
After the document is prepared, we will insert it into a collection.
employee.insert(employeeDetails);
In order to query the insert document, call find()
on the collection which returns a cursor to iterate through.
DBCursor cursor = employee.find();
If you want to remove a document from the collection call DBCollection.remove(document object)
:
employee.remove(object);
MongoDBExample:
package com.javacodegeeks.spring.mongodb; import java.net.UnknownHostException; import com.mongodb.BasicDBObject; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.mongodb.Mongo; import com.mongodb.MongoClient; public class MongoDBExample { public static void main(String[] args) throws UnknownHostException { Mongo mongo = new MongoClient(); DB db = mongo.getDB("database"); DBCollection employee = db.getCollection("employees"); DBObject employeeDetails = new BasicDBObject() .append("name", "Joe") .append("age", 41) .append("company", new BasicDBObject().append("name", "ABC")); employee.insert(employeeDetails); DBCursor cursor = employee.find(); try { while (cursor.hasNext()) { DBObject object = cursor.next(); System.out.println(object); employee.remove(object); } } finally { cursor.close(); } } }
Output:
{ "_id" : { "$oid" : "56823f0efd80b8af382a0575"} , "name" : "Joe" , "age" : 41 , "company" : { "name" : "ABC"}}
4. Spring MongoDB Configuration
In order to create the MongoDB configuration, we can simply extend the AbstractMongoConfiguration
class, which contains a lot of the basic configuration which we can tweak to our needs by overriding methods. What does AbstractMongoConfiguration
do and what are the important methods to override?
- Scans the mapping base package for classes annotated with
@Document
. - We will override
mongo()
to return theMongo
instance to connect to. We will also annotate it with@Bean
so that the instance can be fetched from theApplicationContext
. - Other important method to override is
getDatabaseName()>
. Using the database name, and theMongo
instance,AbstractMongoConfiguration
creates a default instance ofMongoDbFactory
which in turn is referred to by theMongoTemplate
which is our next topic of discussion. WriteConcern
controls the acknowledgment of write operations. This will cause all write operations invoked through the template to be executed with the configured concern.
SpringMongoConfig:
package com.javacodegeeks.spring.mongodb; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.config.AbstractMongoConfiguration; import com.mongodb.Mongo; import com.mongodb.MongoClient; import com.mongodb.WriteConcern; @Configuration public class SpringMongoConfig extends AbstractMongoConfiguration { @Override protected String getDatabaseName() { return "database"; } @Override @Bean public Mongo mongo() throws Exception { Mongo mongo = new MongoClient(); mongo.setWriteConcern(WriteConcern.ACKNOWLEDGED); return mongo; } }
5. Spring MongoTemplate
MongoTemplate
is the spring provided implementation of MongoOperations
which in turn specifies a basic set of MongoDB operations.
In the below definition of the interface you can see some of the important methods that allows us to insert/update/query and remove objects.
MongoOperations:
public interface MongoOperations { ... void insert(Object objectToSave); void save(Object objectToSave); WriteResult updateFirst(Query query, Update update, Class entityClass); WriteResult remove(Query query, Class entityClass); ... }
6. Spring MongoDB XML Configuration
Here is the XML version of the configuration.
applicationContext.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:mongo="http://www.springframework.org/schema/data/mongo" xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <mongo:db-factory id="mongoDbFactory" dbname="database" /> <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg ref="mongoDbFactory" /> <property name="writeConcern" value="ACKNOWLEDGED" /> </bean> </beans>
The <db-factory/>
element sets up the MongoDBFactory
by instantiating SimpleMongoDbFactory
. Using the mongoDbFactory
bean we create the MongoTemplate
bean. Note that WriteConcern
is passed value ACKNOWLEDGED
. We need this so that any issues in network or server errors and treated as exceptions.
7. Domain Model
Out model consists of an employee with id
, name
, age
and company
attributes. We have two POJOs Employee
and Company
.
We will annotate the POJOs to be persisted with @Document
. @Document
annotation identifies a domain object to be persisted to MongoDB.
@DBRef
annotation indicates the annotated field to be stored as a reference to another document.
Employee:
package com.javacodegeeks.spring.mongodb; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.DBRef; import org.springframework.data.mongodb.core.mapping.Document; @Document(collection = "employees") public class Employee { @Id private String id; private String name; private Integer age; @DBRef private Company company; public Employee(){} public Employee(String id, String name, Company company) { this.id = id; this.name = name; this.company = company; } 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 Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Company getCompany() { return company; } public void setCompany(Company company) { this.company = company; } public String toString() { return "Employee [" + getId() + ", " + getName() + ", " + getCompany() + "]"; } }
Company:
package com.javacodegeeks.spring.mongodb; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @Document public class Company { @Id private String name; public Company(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString() { return "Company [" + getName() + "]"; } }
8. Spring MongoDB CRUD Example
In our spring MongoDB example, we will first load the spring container. We can either load the applicationContext XML or the annotated JavaConfig class SpringMongoConfig
.
In this example, we will use the annotated version of configuration.
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext( SpringMongoConfig.class);
Once we have the spring context object, we will get the MongoTemplate
bean.
MongoOperations mongoOperation = (MongoOperations) ctx .getBean("mongoTemplate");
Next, we will create the company object sand save them. We will have two companies ‘ABC’ and ‘XYZ’.
Company abcCompany = new Company("ABC"); mongoOperation.save(abcCompany);
Next, we will create three employees. Two of them belong to ‘ABC’ and the third one to ‘XYZ’.
Employee empJoe = new Employee("01", "Joe", abcCompany); Employee empSam = new Employee("02", "Sam", abcCompany); Employee empJohn = new Employee("03", "John", xyzCompany); mongoOperation.save(empJoe); mongoOperation.save(empSam); mongoOperation.save(empJohn);
Next operation is to find the employees inserted.
Query searchUserQuery = new Query(Criteria.where("company").is( abcCompany)); List abcEmployees = mongoOperation.find(searchUserQuery, Employee.class); System.out.println("ABC Employees : " + abcEmployees);
Employee working for ‘XYZ’ resigns and now join ‘ABC’. We will update the company of employee from ‘XYZ’ to ‘ABC’.
System.out.println("Update John's company to " + xyzCompany); mongoOperation.updateFirst(new Query(Criteria.where("company").is(xyzCompany)), Update.update("company", abcCompany), Employee.class);
Finally, remove the employees.
System.out.println("Remove all employees"); mongoOperation.remove(new Query(Criteria.where("company").is(abcCompany)), Employee.class);
SpringMongoDBExample:
package com.javacodegeeks.spring.mongodb; import java.net.URISyntaxException; import java.util.List; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; public class SpringMongoDBExample { public static void main(String[] args) throws URISyntaxException, Exception { ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext( SpringMongoConfig.class); try { MongoOperations mongoOperation = (MongoOperations) ctx .getBean("mongoTemplate"); Company abcCompany = new Company("ABC"); mongoOperation.save(abcCompany); Company xyzCompany = new Company("XYZ"); mongoOperation.save(xyzCompany); Employee empJoe = new Employee("01", "Joe", abcCompany); Employee empSam = new Employee("02", "Sam", abcCompany); Employee empJohn = new Employee("03", "John", xyzCompany); mongoOperation.save(empJoe); mongoOperation.save(empSam); mongoOperation.save(empJohn); System.out.println("Employees added: " + empJoe + ", " + empSam + ", " + empJohn); Query searchUserQuery = new Query(Criteria.where("company").is( abcCompany)); List abcEmployees = mongoOperation.find(searchUserQuery, Employee.class); System.out.println("ABC Employees : " + abcEmployees); System.out.println("Update John's company to " + xyzCompany); mongoOperation.updateFirst( new Query(Criteria.where("company").is(xyzCompany)), Update.update("company", abcCompany), Employee.class); abcEmployees = mongoOperation.find(searchUserQuery, Employee.class); System.out.println("ABC Employees after update: " + abcEmployees); System.out.println("Remove all employees"); mongoOperation.remove( new Query(Criteria.where("company").is(abcCompany)), Employee.class); abcEmployees = mongoOperation.find(searchUserQuery, Employee.class); System.out.println("ABC Employees after remove: " + abcEmployees.size()); } finally { ctx.close(); } } }
Output:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Employees added: Employee [01, Joe, Company [ABC]], Employee [02, Sam, Company [ABC]], Employee [03, John, Company [XYZ]] ABC Employees : [Employee [01, Joe, Company [ABC]], Employee [02, Sam, Company [ABC]]] Update John's company to Company [XYZ] ABC Employees after update: [Employee [01, Joe, Company [ABC]], Employee [02, Sam, Company [ABC]], Employee [03, John, Company [ABC]]] Remove all employees ABC Employees after remove: 0
9. Spring XML MongoDB Example
You can also load the spring XML context and then get the MongoOperations
bean from the loaded context.
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Now get the MongoTemplate
.
MongoOperations mongoOperation = (MongoOperations) ctx .getBean("mongoTemplate");
SpringXMLMongoDBExample:
package com.javacodegeeks.spring.mongodb; import java.net.URISyntaxException; import java.util.List; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; public class SpringXMLMongoDBExample { public static void main(String[] args) throws URISyntaxException, Exception { ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); try { MongoOperations mongoOperation = (MongoOperations) ctx .getBean("mongoTemplate"); Company abcCompany = new Company("ABC"); mongoOperation.save(abcCompany); Company xyzCompany = new Company("XYZ"); mongoOperation.save(xyzCompany); Employee empJoe = new Employee("01", "Joe", abcCompany); Employee empSam = new Employee("02", "Sam", abcCompany); Employee empJohn = new Employee("03", "John", xyzCompany); mongoOperation.save(empJoe); mongoOperation.save(empSam); mongoOperation.save(empJohn); System.out.println("Employees added: " + empJoe + ", " + empSam + ", " + empJohn); Query searchUserQuery = new Query(Criteria.where("company").is( abcCompany)); List abcEmployees = mongoOperation.find(searchUserQuery, Employee.class); System.out.println("ABC Employees : " + abcEmployees); System.out.println("Update John's company to " + xyzCompany); mongoOperation.updateFirst( new Query(Criteria.where("company").is(xyzCompany)), Update.update("company", abcCompany), Employee.class); abcEmployees = mongoOperation.find(searchUserQuery, Employee.class); System.out.println("ABC Employees after update: " + abcEmployees); System.out.println("Remove all employees"); mongoOperation.remove( new Query(Criteria.where("company").is(abcCompany)), Employee.class); abcEmployees = mongoOperation.find(searchUserQuery, Employee.class); System.out.println("ABC Employees after remove: " + abcEmployees.size()); } finally { ctx.close(); } } }
Output:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Employees added: Employee [01, Joe, Company [ABC]], Employee [02, Sam, Company [ABC]], Employee [03, John, Company [XYZ]] ABC Employees : [Employee [01, Joe, Company [ABC]], Employee [02, Sam, Company [ABC]]] Update John's company to Company [XYZ] ABC Employees after update: [Employee [01, Joe, Company [ABC]], Employee [02, Sam, Company [ABC]], Employee [03, John, Company [ABC]]] Remove all employees ABC Employees after remove: 0
10. Download Eclipse Project
This was an example about Spring MongoDB.
You can download the full source code of this example here: springMongoDBExample.zip