Before we start, please download and run MongoDB for your operating system. It’s very simple so I won’t spend time on this and let’s start with simple POM file for our project:
4.0.0
mongodb
com.example.spring
0.0.1-SNAPSHOT
jar
UTF-8
3.0.5.RELEASE
org.springframework.data
spring-data-mongodb
1.0.0.M3
log4j
log4j
1.2.16
org.mongodb
mongo-java-driver
2.5.3
org.springframework
spring-core
${spring.version}
org.springframework
spring-context
${spring.version}
springsource-milestone
Spring Framework Milestone Repository
http://maven.springframework.org/milestone
There are two key dependencies here:
- MongoDB java driver
- Spring Data for MongoDB
There are few ways to define MongoDB inside your Spring application context. Let me show a bit verbose but more flexible one:
<beans xmlns:context="http://www.springframework.org/schema/context" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<constructor-arg index="0" ref="mongo" />
<constructor-arg index="1" value="elements-db"/>
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mappingContext" />
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="converter" />
<property name="writeResultChecking" value="EXCEPTION" />
<property name="writeConcern" value="NORMAL"/>
The role of each bean here:
- mongo defines connection to MongoDB database (we rely on default settings, port 27027)
- converter is used to convert Java classes to/from MongoDB’s DBObject (== JSON)
- mongoTemplate exposes operations we can do over MongoDB
So, we are ready to go!
Here are few code snippets to start with:
package com.example.mongodb;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.document.mongodb.CollectionCallback;
import org.springframework.data.document.mongodb.MongoOperations;
import org.springframework.data.document.mongodb.query.Index;
import org.springframework.data.document.mongodb.query.Index.Duplicates;
import org.springframework.data.document.mongodb.query.Order;
import org.springframework.stereotype.Service;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;
@Service
public class MongoService {
@Autowired private MongoOperations template;
public void createCollection( final String name ) {
template.createCollection( name );
}
public void dropCollection( final String name ) {
template.dropCollection( name );
}
public void insert( final Object object, final String collection ) {
template.insert( object, collection );
}
public void createIndex( final String name, final String collection ) {
template.ensureIndex(
new Index()
.on( name, Order.DESCENDING )
.unique( Duplicates.DROP ),
collection
);
}
// Remove / save / ... operations here
}
That’s it with basics. Next post will cover advanced features: using bulk inserts, update or insert operation and executing MongoDB commands. ![]()
After the discussion about MongoDB and Spring Data projects, i would like to show some advanced features (which could be available in next Spring Data milestone or release as part of core functionality).
First of all, let us extend our MongoService with a method that counts documents in collection which match specific query.
package com.example.mongodb;
import java.util.Arrays;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.document.mongodb.CollectionCallback;
import org.springframework.data.document.mongodb.MongoOperations;
import org.springframework.data.document.mongodb.convert.MongoConverter;
import org.springframework.data.document.mongodb.query.Criteria;
import org.springframework.data.document.mongodb.query.Index;
import org.springframework.data.document.mongodb.query.Index.Duplicates;
import org.springframework.data.document.mongodb.query.Order;
import org.springframework.data.document.mongodb.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;
@Service
public class MongoService {
public long countDocuments( final String collection, final Query query ) {
return template.executeCommand(
"{ " +
"\"count\" : \"" + collection + "\"," +
"\"query\" : " + query.getQueryObject().toString() +
" }" ).getLong( "n" );
}
}
The approach for this particular functionality is to call native MongoDB command count passing the query as a parameter. The returning structure contains number of documents in n property.
Or, in more code-friendly way:
import org.springframework.dao.DataAccessException;
import org.springframework.data.document.mongodb.CollectionCallback;
import com.mongodb.DBCollection;
import com.mongodb.MongoException;
public long countDocuments( final String collection, final Query query ) {
return template.execute( collection,
new CollectionCallback< Long >() {
@Override
public Long doInCollection( DBCollection collection )
throws MongoException, DataAccessException {
return collection.count( q.getQueryObject() ) );
}
}
);
}
Next useful feature is bulk inserts. Please note, that in current version of MongoDB 1.8.1, when there is a duplicate inside the collection of inserting documents, bulk insert stops on first duplicate and returns so all other documents won’t be inserted. Be aware of such behavior. Before moving to code snippet, let me introduce simple class SimpleDocument which we will be persisting to MongoDB:
package com.example.mongodb;
import org.springframework.data.document.mongodb.mapping.Document;
@Document( collection = "documents" )
public class SimpleDocument {
private String id;
private String name;
private String content;
public SimpleDocument() {
}
public SimpleDocument( final String id, final String name ) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
Following method inserts all documents as single bulk update:
public void insert( final Collection< SimpleDocument > documents ) {
template.insert( documents, SimpleDocument.class );
}
Another very cool and useful feature to explore is MongoDB’s upserts (more about this here http://www.mongodb.org/display/DOCS/Updating): if document matching specific criteria exists, it will be updated, otherwise – new document will be inserted into collection. Here is a code snipped with demonstrates it by following use case: if SimpleDocument with such name exists, it will be updated, otherwise new document will be added to collection:
@Autowired private MongoConverter converter;
public void insertOrUpdate( final SimpleDocument document ) {
final BasicDBObject dbDoc = new BasicDBObject();
converter.write( document, dbDoc );
template.execute( SimpleDocument.class,
new CollectionCallback< Object >() {
public Object doInCollection( DBCollection collection )
throws MongoException, DataAccessException {
collection.update(
new Query()
.addCriteria( new Criteria( "name" ).is( document.getName() ) )
.getQueryObject(),
dbDoc,
true,
false
);
return null;
}
}
);
}
Please notice usage of converter bean which helps to convert Java class to MongoDB’s DBObject.
The last one I would like to show is findAndModify operation which does several things as one atomic sequence:
- find document matching criteria
- perform update
- return updated document (or old one, depending on what are your needs)
public void findAndModify( final Query query, final Update update ) {
return template.execute( SimpleDocument.class,
new CollectionCallback< SimpleDocument >() {
@Override
public SimpleDocument doInCollection( DBCollection collection )
throws MongoException, DataAccessException {
return converter.read( SimpleDocument.class,
collection.findAndModify(
query.getQueryObject(),
null,
null,
false,
update.getUpdateObject(),
true,
false
)
);
}
}
);
}
For now, those are all interesting use cases I encountered. Honestly, I am very excited about MongoDB and strongly recommend it if it fits your application.
Reference: Exploiting MongoDB together with Spring Data project: basic concepts & Exploiting MongoDB together with Spring Data project: advanced concepts from our JCG partner Andrey Redko at the Andriy Redko {devmind} blog.




