spring

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.

  1. Download MongoDB.
  2. Ensure you download the correct version of mongoDB. In my case it is MongoDB for windows 64-bit 2008 R2+
  3. 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.
  4. Create a data directory to store the data files. We have created data folder within the mongoDB directory.
    C:\mongodb\bin>mongod.exe --dbpath "C:\mongodb\data"
    
  5. 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?

  1. Scans the mapping base package for classes annotated with @Document.
  2. We will override mongo() to return the Mongo instance to connect to. We will also annotate it with @Bean so that the instance can be fetched from the ApplicationContext.
  3. Other important method to override is getDatabaseName()>. Using the database name, and the Mongo instance, AbstractMongoConfiguration creates a default instance of MongoDbFactory which in turn is referred to by the MongoTemplate which is our next topic of discussion.
  4. 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.

Download
You can download the full source code of this example here: springMongoDBExample.zip

Ram Mokkapaty

Ram holds a master's degree in Machine Design from IT B.H.U. His expertise lies in test driven development and re-factoring. He is passionate about open source technologies and actively blogs on various java and open-source technologies like spring. He works as a principal Engineer in the logistics domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button