MongoDB supportThe MongoDB support contains a wide range of features which are
summarized below.Spring configuration support using Java based @Configuration
classes or an XML namespace for a Mongo driver instance and replica
setsMongoTemplate helper class that increases productivity performing
common Mongo operations. Includes integrated object mapping between
documents and POJOs.Exception translation into Spring's portable Data Access Exception
hierarchyFeature Rich Object Mapping integrated with Spring's Conversion
ServiceAnnotation based mapping metadata but extensible to support other
metadata formatsPersistence and mapping lifecycle eventsJava based Query, Criteria, and Update DSLsAutomatic implementatin of Repository interfaces including support
for custom finder methods.QueryDSL integration to support type-safe queries.Cross-store persistance - support for JPA Entities with fields
transparently persisted/retrieved using MongoDBLog4j log appenderGeoSpatial integrationFor most tasks you will find yourself using
MongoTemplate or the Repository support that both
leverage the rich mapping functionality. MongoTemplate is the place to look
for accessing functionality such as incrementing counters or ad-hoc CRUD
operations. MongoTemplate also provides callback methods so that it is easy
for you to get a hold of the low level API artifacts such as
org.mongo.DB to communicate directly with MongoDB. The
goal with naming conventions on various API artifacts is to copy those in
the base MongoDB Java driver so you can easily map your existing knowledge
onto the Spring APIs.Getting StartedSpring MongoDB support requires MongoDB 1.4 or higher and Java SE 5
or higher. The latest production release (1.8.x as of this writing) is
recommended. An easy way to bootstrap setting up a working environment is
to create a Spring based project in STS.First you need to set up a running Mongodb server. Refer to the
Mongodb Quick
Start guide for an explanation on how to startup a Mongo instance.
Once installed starting Mongo is typically a matter of executing the
following command: MONGO_HOME/bin/mongodTo create a Spring project in STS go to File -> New -> Spring
Template Project -> Simple Spring Utility Project --> press Yes when
prompted. Then enter a project and a package name such as
org.spring.mongodb.example.Then add the following to pom.xml dependencies section.<dependencies>
<!-- other dependency elements omitted -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.0.0.M3</version>
</dependency>
</dependencies>
Also change the version of Spring in the pom.xml to be<spring.framework.version>3.0.5.RELEASE</spring.framework.version>You will also need to add the location of the Spring Milestone
repository for maven to your pom.xml which is at the same level of your
<dependencies/> element<repositories>
<repository>
<id>spring-milestone</id>
<name>Spring Maven MILESTONE Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository>
</repositories>The repository is also browseable
here.You may also want to set the logging level to DEBUG to see some
additional information, edit the log4j.properties file to havelog4j.category.org.springframework.data.document.mongodb=DEBUG
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%nCreate a simple Person class to persistpackage org.spring.mongodb.example;
public class Person {
private String id;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}And a main application to runpackage org.spring.mongodb.example;
import static org.springframework.data.document.mongodb.query.Criteria.where;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.document.mongodb.MongoOperations;
import org.springframework.data.document.mongodb.MongoTemplate;
import org.springframework.data.document.mongodb.query.Query;
import com.mongodb.Mongo;
public class MongoApp {
private static final Log log = LogFactory.getLog(MongoApp.class);
public static void main(String[] args) throws Exception {
MongoOperations mongoOps = new MongoTemplate(new Mongo(), "database");
mongoOps.insert(new Person("Joe", 34));
log.info(mongoOps.findOne(new Query(where("name").is("Joe")), Person.class));
mongoOps.dropCollection("person");
}
}This will produce the following output10:01:32,062 DEBUG apping.MongoPersistentEntityIndexCreator: 80 - Analyzing class class org.spring.example.Person for index information.
10:01:32,265 DEBUG work.data.document.mongodb.MongoTemplate: 631 - insert DBObject containing fields: [_class, age, name] in collection: Person
10:01:32,765 DEBUG work.data.document.mongodb.MongoTemplate:1243 - findOne using query: { "name" : "Joe"} in db.collection: database.Person
10:01:32,953 INFO org.spring.mongodb.example.MongoApp: 25 - Person [id=4ddbba3c0be56b7e1b210166, name=Joe, age=34]
10:01:32,984 DEBUG work.data.document.mongodb.MongoTemplate: 375 - Dropped collection [database.person]Even in this simple example, there are few things to take notice
ofYou can instantiate the central helper class of Spring Mongo,
MongoTemplate, using the
standard com.mongodb.Mongo object and the name
of the database to use.The mapper works against standard POJO objects without the need
for any additional metadata (though you can optionally provide that
information. See here.).Conventions are used for handling the id field, converting it to
be a ObjectId when stored in the database.Mapping conventions can use field access. Notice the Person
class has only getters.If the constructor argument names match the field names of the
stored document, they will be used to instantiate the objectRequired Jars
The following jars are required to use Sping Mongo
spring-data-mongodb-1.0.0.M3.jar
In addition to the above listed Spring Data jars you need to provide the following dependencies:
com.springsource.org.aopalliance-1.0.0.jarcommons-logging-1.1.1.jarmongo-java-driver-2.5.3.jarspring-aop-3.0.5.RELEASE.jarspring-asm-3.0.5.RELEASE.jarspring-beans-3.0.5.RELEASE.jarspring-context-3I.0.5.RELEASE.jarspring-core-3.0.5.RELEASE.jarspring-expression-3.0.5.RELEASE.jarExamples RepositoryThere is an github
repository with several examples that you can download and play
around with to get a feel for how the library works.Connecting to MongoDB with SpringOne of the first tasks when using MongoDB and Spring is to create a
com.mongodb.Mongo object using the IoC container.
There are two main ways to do this, either using Java based bean metadata
or XML based bean metadata. These are discussed in the following sections.
For those not familiar with how to configure the Spring
container using Java based bean metadata instead of XML based metadata
see the high level introduction in the reference docs here as well as the detailed documentation
here.Registering a Mongo instance using Java based metadataAn example of using Java based bean metadata to register an
instance of a com.mongodb.Mongo is shown below
Registering a com.mongodb.Mongo object using Java based bean
metadata@Configuration
public class AppConfig {
/*
* Use the standard Mongo driver API to create a com.mongodb.Mongo instance.
*/
public @Bean Mongo mongo() throws UnknownHostException {
return new Mongo("localhost");
}
} This approach allows you to use the standard
com.mongodb.Mongo API that you may already be
used to using but also pollutes the code with the UnknownHostException
checked exception. The use of the checked exception is not desirable as
Java based bean metadata uses methods as a means to set object
dependencies, making the calling code cluttered.An alternative is to register an instance of
com.mongodb.Mongo instance with the container
using Spring's MongoFactoryBean. As
compared to instantiating a com.mongodb.Mongo
instance directly, the FactoryBean approach does not throw a checked
exception and has the added advantage of also providing the container
with an ExceptionTranslator implementation that translates Mongo
exceptions to exceptions in Spring's portable
DataAccessException hierarchy for data access
classes annoated with the @Repository annotation.
This hierarchy and use of @Repository is described in
Spring's
DAO support features.An example of a Java based bean metadata that supports exception
translation on @Repository annotated classes is
shown below:Registering a com.mongodb.Mongo object using Spring's
MongoFactoryBean and enabling Spring's exception translation
support@Configuration
public class AppConfig {
/*
* Factory bean that creates the com.mongodb.Mongo instance
*/
public @Bean MongoFactoryBean mongo() {
MongoFactoryBean mongo = new MongoFactoryBean();
mongo.setHost("localhost");
return mongo;
}
}
To access the com.mongodb.Mongo object
created by the MongoFactoryBean in other
@Configuration or your own classes, use a
"private @Autowired Mongo mongo;" field.Registering a Mongo instance using XML based metadataWhile you can use Spring's traditional
<beans/> XML namespace to register an instance
of com.mongodb.Mongo with the container, the XML
can be quite verbose as it is general purpose. XML namespaces are a
better alternative to configuring commonly used objects such as the
Mongo instance. The mongo namespace alows you to create a Mongo instance
server location, replica-sets, and options.To use the Mongo namespace elements you will need to reference the
Mongo schema:XML schema to configure MongoDB<?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/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">
<!-- Default bean name is 'mongo' -->
<mongo:mongo host="localhost" port="27017"/>
</beans>
A more advanced configuration with MongoOptions is shown below
(note these are not recommended values)XML schema to configure a com.mongodb.Mongo object with
MongoOptions<beans>
<mongo:mongo host="localhost" port="27017">
<mongo:options connections-per-host="8"
threads-allowed-to-block-for-connection-multiplier="4"
connect-timeout="1000"
max-wait-time="1500}"
auto-connect-retry="true"
socket-keep-alive="true"
socket-timeout="1500"
slave-ok="true"
write-number="1"
write-timeout="0"
write-fsync="true"/>
</mongo:mongo/>
</beans>
A configuration using replica sets is shown below. XML schema to configure com.mongodb.Mongo object with Replica
Sets<mongo:mongo id="replicaSetMongo" replica-set="127.0.0.1:27017,localhost:27018"/> Registering a MongoDbFactory instance using Java based
metadataAs an alternative to configuring a
com.mongodb.Mongo instance and later providing
the database name and optionally the username and password, is to use
SimpleMongoDbFactory, which implements the
MongoDbFactory inteface shown below. A
reference to MongoDbFactory can be passed
to constructors of MongoTemplate to simplify its
creation.public interface MongoDbFactory {
DB getDb() throws DataAccessException;
DB getDb(String dbName) throws DataAccessException;
}The most simple usage is shown below@Configuration
public class MongoConfiguration {
public @Bean MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(new Mongo(), "database");
}
}To define the username and password create an instance of
org.springframework.data.authentication.UserCredentials and pass it into
the constructor as shown below@Configuration
public class MongoConfiguration {
public @Bean MongoDbFactory mongoDbFactory() throws Exception {
UserCredentials userCredentials = new UserCredentials("joe", "secret");
return new SimpleMongoDbFactory(new Mongo(), "database", userCredentials);
}
}
Registering a Mongo instance using XML based metadataThe mongo namespace lets you create a MongoDbFactory instance
which is a convenient way to group together the a mongo instance, a
database name and an optional username and password. A simple usage is
shown below <mongo:db-factory dbname="database" >Introduction to MongoTemplateThe class MongoTemplate, located in the
package org.springframework.data.document.mongodb, is
the central class of the Spring's MongoDB support providng a rich feature
set. The template offers convenience operations to create, update, delete
and query for MongoDB document and provide a mapping between your domain
objects and MongoDB documents.Once configured, MongoTemplate is
thread-safe and can be reused across multiple instances.The mapping between Mongo documents and domain classes is done by
delegating to an implementation of the interface
MongoConverter. Spring provides two
implementations, SimpleMappingConverter and
MongoMappingConverter, but you can also write your
own converter. Please refer to the section on MongoCoverters for more
detailed information.The MongoTemplate class implements the
interface MongoOperations. In as much as
possible, the methods on MongoOperations
are named after methods available on the MongoDB driver
Collection object. For example, you will find
methods such as "find", "findAndModify", "findOne", "insert", "remove",
"save", "update" and "updateMulti". The design goal was to make it as easy
as possible to transition between the use of the base MongoDB driver and
MongoOperations. The difference in betwee
the two is that MongOperations can be passed domain objects instead of
DBObject and there are fluent APIs for
Query, Criteria, and
Update operations instead of
DBObject..The preferred way to reference the operations on
MongoTemplate instance is via its interface
MongoOperations.The default converter implementation used by
MongoTemplate is
SimpleMappingConverter, which as the name implies,
is simple. SimpleMapingConverter does not use any
additional mapping metadata to converter a domain object to a MongoDB
document. As such, it does not support functionality such as DBRefs or
creating indexes using annotations on domain classes. For a detailed
description of the MongoMappingConverter read the section on Mapping Support.Another central feature of MongoTemplate is exception translation of
exceptions thrown in the Mongo Java driver into Spring's portable Data
Access Exception hierarchy. Refer to the section on exception translation for more
information.While there are many convenience methods on
MongoTemplate to help you easily perform common
tasks if you should need to access the Mongo driver API directly to access
functionality not explicitly exposed by the MongoTemplate you can use one
of several Execute callback methods. These will give you a reference to a
Mongo Collection or DB object. Please see the section Execution Callbacks for more
information.Now let's look at a examples of how to work with the
MongoTemplate in the context of the Spring
container.Instantiating MongoTemplateYou can use Java to create and register an instance of
MongoTemplate as shown below.Registering a com.mongodb.Mongo object and enabling Spring's
exception translation support@Configuration
public class AppConfig {
public @Bean Mongo mongo() throws Exception {
return new Mongo("localhost");
}
public @Bean MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongo(), "mydatabase", "mycollection");
}
}
There are several overloaded constructors of MongoTemplate. These
areMongoTemplate (Mongo mongo, String databaseName) - takes the
default database name to operate againstMongoTemplate (Mongo mongo, String databaseName, String
defaultCollectionName) - adds the default collection name
to operate against.MongoTemplate (Mongo mongo, String databaseName, String
defaultCollectionName, MongoConverter mongoConverter) -
override with a provided MongoConverter. Default is
SimpleMongoConverterYou can also configure a MongoTemplate using Spring's XML
<beans/> schema. <mongo:mongo host="localhost" port="27017"/>
<bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate">
<constructor-arg ref="mongo"/>
<constructor-arg name="databaseName" value="geospatial"/>
<constructor-arg name="defaultCollectionName" value="newyork"/>
</bean>Other properties that you might like to set when creating a
MongTemplate are WriteResultCheckingPolicy and the default
WriteConcern.The preferred way to reference the operations on
MongoTemplate instance is via its interface
MongoOperations.WriteResultChecking PolicyWhen in development it is very handy to either log or throw an
exception if the WriteResult returned from any MongoDB operation
contains an error. It is quite common to forget to do this during
development and then end up with an application that looks like it ran
successfully but the database was not modified according to your
expectations. Setting the WriteResultChecking is an enum with the
following values, NONE, LOG, EXCEPTION.The default is to use a WriteResultChecking of NONE.WriteConcernYou can set the WriteConcern property that the MongoTemplate
will use for write operations if it has not yet been specifid with the
driver. If not set, it will default to the one set in the MongoDB
driver's DB or Collection setting.Setting the WriteConcern to different values when saving an
object will be provided in a future release. This will most likely
be handled using mapping metadata provided either in the form of
annotations on the domain object or by an external fluent
DSL.Configuring the MongoConverterThe SimpleMongoConverter is used by default but if you want to use
the more feature rich MappingMongoConverter there are a few steps.
Please refer to the mapping section for more
information.Saving, Updating, and Removing DocumentsMongoTemplate provides a simple way for you
to save, update, and delete your domain objects and map those objects to
documents stored in MongoDB.Given a simple class such as Personpublic class Person {
private String id;
private String firstName;
private int age;
// getters and setter omitted
}You can save, update and delete the object as shown below.MongoOperations is the interface
that MongoTemplate implements.public class PersonExample {
private static final Log log = LogFactory.getLog(PersonExample.class);
@Autowired
private MongoOperations mongoOps;
public void doWork() {
Person p = new Person();
p.setFirstName("Sven");
p.setAge(22);
// Save
mongoOps.save(p);
log.debug("Saved: " + p);
// Find
p = mongoOps.findOne(query(whereId().is(p.getId())), Person.class);
log.debug("Found: " + p);
// Update age to 24 for Sven
mongoOps.updateFirst(query(where("firstName").is("Sven")), update("age", 24));
p = mongoOps.findOne(query(whereId().is(p.getId())), Person.class);
log.debug("Updated: " + p);
// Delete
mongoOps.remove(p);
// Check that deletion worked
List<Person> people = mongoOps.getCollection(Person.class);
log.debug("Number of people = : " + people.size());
}This would produce the following log output (including some debug
message from MongoTemplate itself)Saved: PersonWithIdPropertyOfTypeString [id=4d9e82ac94fa72c65a9e7d5f, firstName=Sven, age=22]
findOne using query: { "_id" : { "$oid" : "4d9e82ac94fa72c65a9e7d5f"}} in db.collection: database.personexample
Found: PersonWithIdPropertyOfTypeString [id=4d9e82ac94fa72c65a9e7d5f, firstName=Sven, age=22]
findOne using query: { "_id" : { "$oid" : "4d9e82ac94fa72c65a9e7d5f"}} in db.collection: database.personexample
Updated: PersonWithIdPropertyOfTypeString [id=4d9e82ac94fa72c65a9e7d5f, firstName=Sven, age=24]
remove using query: { "_id" : { "$oid" : "4d9e82ac94fa72c65a9e7d5f"}}
Number of people = : 0There was implicit conversion using the MongoConverter between a
String and ObjectId as stored in the database and recognizing a convention
of the property "Id" name.This example is meant to show the use of save, update and remove
operations on MongoTemplate and not to show complex mapping
functionalityThe query stynax used in the example is explained in more detail in
the section Querying Documents.How the '_id' field is handled in the mapping layerMongo requires that you have an '_id' field for all documents. If
you don't provide one the driver will assign a ObjectId with a generated
value. When using the MongoMappingConverter there
are certain rules that govern how properties from the Java class is
mapped to this '_id' field.The following outlines what property will be mapped to the '_id'
field:A property or field annotated with
@Id
(org.springframework.data.annotation.Id)
will be mapped to the '_id' field.A property or field named id will be
mapped to the '_id' field.A property or field declared as a String in the Java class
will be converted to and stored as an ObjectId if possible
(conversions and rules would be handled by the Mongo Java driver).
If it cannot be converted to an ObjectId, then the value will be
stored as a string in the database.A property or field declared as anything but a String in the
Java class will be stored as the type it is declared as, which
means it must be one of the basic types supported by the Mongo
Java driver.If no field or property specified above is present in the Java
class then an implicit '_id' file will be generated by the driver but
not mapped to a property or field of the Java class.When querying and updating the JdbcTemplate
will use the converter to handle conversions of the
Query and Update objects
that correspond to the above rules for saving documents so field names
and types used in your queries will be able to match what is in your
domain classes.Methods for saving and inserting documentsThere are several convenient methods on MongoTemplate for saving
and inserting your objects. In addition to using a
MongoCoverter to converter your domain
object to the database, you can also use an implementation of the
MongoWriter interface to have very fine
grained control over the conversion process.The difference between insert and save operations is that a save
operation will perform an insert if the object is not already
present.The simple case of using the save operation is to pass in as an
argument only the object to save. In this case the default collection
assigned to the template will be used unless the converter overrides
this default through the use of more specific mapping metadata. You may
also call the save operation with a specific collection name.When inserting or saving, if the Id property is not set, the
assumption is that its value will be autogenerated by the database. As
such, for autogeneration of an ObjectId to succeed the type of the Id
property/field in your class must be either a
String, ObjectId, or
BigInteger.Here is a basic example of using the save operation and retrieving
its contents.Inserting and retrieving documents using the
MongoTemplateimport static org.springframework.data.document.mongodb.query.Criteria.where;
import static org.springframework.data.document.mongodb.query.Criteria.query;
...
Person p = new Person("Bob", 33);
mongoTemplate.insert("MyCollection", p);
Person qp = mongoTemplate.findOne("MyCollection", query(where("age").is(33)), Person.class);
The four save operations available to you are listed below.voidsave
(Object objectToSave) Save the
object to the default collection.voidsave
(String collectionName, Object objectToSave)
Save the object to the specified collection.<T> voidsave
(T objectToSave, MongoWriter<T> writer)
Save the object into the default collection using the
provided writer.<T> voidsave
(String collectionName, T objectToSave,
MongoWriter<T> writer) Save the object into the
specified collection using the provided writer.A similar set of insert operations is listed belowvoidinsert(Object objectToSave)
Insert the object to the default collection.voidinsert
(String collectionName, Object objectToSave)
Insert the object to the specified collection.<T> voidinsert (T objectToSave,
MongoWriter<T> writer) Insert the object into the
default collection using the provided writer.<T> voidinsert (String collectionName, T
objectToSave, MongoWriter<T> writer) Insert the
object into the specified collection using the provided
writer.Unless and explicit MongoWriter is passed into the save or insert
method, the the template's MongoConverter will be used.Saving using MongoWriterThe MongoWriter interface allows you to have lower level control
over the mapping of an object into a DBObject. The MongoWriter
interface is/**
* A MongoWriter is responsible for converting an object of type T to the native MongoDB
* representation DBObject.
*
* @param <T> the type of the object to convert to a DBObject
*/
public interface MongoWriter<T> {
/**
* Write the given object of type T to the native MongoDB object representation DBObject.
*
* @param t The object to convert to a DBObject
* @param dbo The DBObject to use for writing.
*/
void write(T t, DBObject dbo);
}Inserting Lists of objects in batchThe MongoDB driver supports inserting a collection of documents
in one operation. The methods in the MongoOperations interface that
support this functionality are listed belowvoidinsertList (List<? extends
Object> listToSave) Insert a
list of objects into the default collection in a single batch
write to the database.voidinsertList(String
collectionName, List<? extends Object>
listToSave)Insert a list of
objects into the specified collection in a single batch write to
the database.<T> voidinsertList (List<? extends
T> listToSave, MongoWriter<T> writer) Insert the object into the default
collection using the provided writer.<T> voidinsertList(String
collectionName, List<? extends T> listToSave,
MongoWriter<T> writer) Insert a list of objects
into the specified collection using the provided MongoWriter
instanceUpdating documents in a collectionFor updates we can elect to update the first document found using
MongoOperation's method
updateFirst or we can update all documents that were
found to match the query using the method
updateMulti. Here is an example of an update of all
SAVINGS accounts where we are adding a one time $50.00 bonus to the
balance using the $inc operator.Updating documents using the MongoTemplateimport static org.springframework.data.document.mongodb.query.Criteria.where;
import static org.springframework.data.document.mongodb.query.Query.query;
import static org.springframework.data.document.mongodb.query.Update
...
WriteResult wr = mongoTemplate.updateMulti(query(where("accounts.accountType").is(Account.Type.SAVINGS)),
update.inc("accounts.$.balance", 50.00));
In addition to the Query discussed above we
provide the update definition using an Update
object. The Update class has methods that match
the update modifiers available for MongoDB.As you can see most methods return the
Update object to provide a fluent style for the
API.Methods for executing updates for documentsWriteResultupdateFirst (Query query,
Update update) Updates the first object that is found
in the default collection that matches the query document with
the provided updated document.WriteResultupdateFirst (String
collectionName, Query query, Update update) Updates
the first object that is found in the specified collection that
matches the query document criteria with the provided updated
document.WriteResultupdateMulti (Query query,
Update update) Updates all objects that are found in
the default collection that matches the query document criteria
with the provided updated document.WriteResultupdateMulti (String
collectionName, Query query, Update update) Updates
all objects that are found in the specified collection that
matches the query document criteria with the provided updated
document.Methods for the Update classUpdateaddToSet
(String key, Object value)
Update using the $addToSet update
modifierUpdateinc
(String key, Number inc) Update
using the $inc update modifierUpdatepop
(String key, Update.Position pos)
Update using the $pop update
modifierUpdatepull
(String key, Object value)
Update using the $pull update modifierUpdatepullAll
(String key, Object[] values)
Update using the $pullAll update
modifierUpdatepush
(String key, Object value)
Update using the $push update modifierUpdatepushAll
(String key, Object[] values)
Update using the $pushAll update
modifierUpdaterename
(String oldName, String newName)
Update using the $rename update
modifierUpdateset
(String key, Object value)
Update using the $set update modifierUpdateunset
(String key) Update using the
$unset update modifierMethods for removing documentsYou can use several overloaded methods to remove an object from
the database.voidremove(Object object)
Remove the given object from the collection by Idvoidremove(Query query)
Remove all documents from the default collection that match the
provided query document criteria.voidremove
(String collectionName, Query query)
Remove all documents from the specified collection that
match the provided query document criteria.<T> void remove(Query query,
Class<T> targetClass) Same behavior as the
remove(Query) method but the Class parameter is used to help
convert the Id of the object if it is present in the query.<T> void remove(String collectionName,
Query query, Class<T> targetClass)Same behavior as
remove(Query, Class) but the Class parameter is used to help
convert the Id of the object if it is present in the uqeryQuerying DocumentsYou can express you queries using the Query and Criteria classes
which have method names that mirror the native MongoDB operator names such
as lt, lte, is, and others. The Query and Criteria classes follow a fluent
API style so that you can easily chain together multiple method criteria
and queries while having easy to understand code. Static imports in Java
are used to help remove the need to see the 'new' keyword for creating
Query and Criteria instances so as to improve readability.GeoSpatial queries are also supported and are described more in the
section GeoSpatial Queries.Querying documents in a collectionWe saw how to retrieve a single document. We can also query for a
collection of documents to be returned as domain objects in a list.
Assuming that we have a number of Person objects with name and age
stored as documents in a collection and that each person has an embedded
account document with a balance. We can now run a query using the
following code.Querying for documents using the MongoTemplateimport static org.springframework.data.document.mongodb.query.Criteria.where;
import static org.springframework.data.document.mongodb.query.Query.query;
...
List<Person> result = mongoTemplate.find(query(where("age").lt(50).and("accounts.balance").gt(1000.00d)),Person.class);
All find methods take a Query object as a
parameter. This object defines the criteria and options used to perform
the query. The criteria is specified using a
Criteria object that has a static factory method
named where used to instantiate a new
Criteria object. We recommend using a static
import for
org.springframework.data.document.mongodb.query.Criteria.where
and Query.query to make the query more
readable.This query should return a list of Person objects that meet the
specified criteria. The Criteria class has the following methods that
correspond to the operators provided in MongoDB.As you can see most methods return the
Criteria object to provide a fluent style for the
API.Methods for the Criteria classCriteriaall
(Object o)Creates a criterion
using the $all operatorCriteriaelemMatch (Criteria c)
Creates a criterion using the
$elemMatch operatorCriteriaexists
(boolean b) Creates a criterion
using the $exists operatorCriteriagt
(Object o)Creates a criterion
using the $gt operatorCriteriagte
(Object o)Creates a criterion
using the $gte operatorCriteriain
(Object... o) Creates a criterion
using the $in operatorCriteriais
(Object o)Creates a criterion
using the $is operatorCriterialt
(Object o)Creates a criterion
using the $lt operatorCriterialte
(Object o)Creates a criterion
using the $lte operatorCriteriamod
(Number value, Number
remainder)Creates a criterion using the
$mod operatorCriterianin
(Object... o) Creates a criterion
using the $nin operatorCriterianot
()Creates a criterion using the
$not meta operator which affects the clause
directly followingCriteriaregex
(String re) Creates a criterion
using a $regexCriteriasize
(int s)Creates a criterion using
the $size operatorCriteriatype
(int t)Creates a criterion using
the $type operatorCriteriaand
(String key) Adds a chained
Criteria with the specified
key to the current
Criteria and retuns the newly created
oneThere are also methods on the Criteria class for geospatial
queries. Here is al isting but look at the section on GeoSpatial Queries to see them in
action.CriteriawithinCenter
(Circle circle)Creates a geospatial
criterion using $within $center operatorsCriteriawithinCenterSphere (Circle circle)
Creates a geospatial criterion using $within
$center operators. This is only available for Mongo 1.7
and higher.CriteriawithinBox
(Box box)Creates a geospatial
criterion using a $within $box operation
Criterianear
(Point point)Creates a geospatial
criterion using a $near operationCriterianearSphere
(Point point) Creates a geospatial
criterion using $nearSphere$center operations.
This is only available for Mongo 1.7 and higher.The Query class has some additional methods
used to provide options for the query.Methods for the Query classQueryaddCriteria
(Criteria criteria) used to add
additional criteria to the queryvoidor(List<Query>
queries) Creates an or query using the
$or operator for all of the provided
queriesFieldfields
() used to define fields to be
included in the query resultsQuerylimit
(int limit) used to limit the
size of the returned results to the provided limit (used for
paging)Queryskip
(int skip) used to skip the
provided number of documents in the results (used for
paging)Sortsort
() used to provide sort
definition for the resultsMethods for querying for documents<T> List<T>getCollection (Class<T>
targetClass) Query for a list of objects of type T from
the default collection.<T> List<T>getCollection (String
collectionName, Class<T> targetClass) Query for a
list of objects of type T from the specified collection.<T> List<T>getCollection (String
collectionName, Class<T> targetClass, MongoReader<T>
reader) Query for a list of objects of type T from the
specified collection, mapping the DBObject using the provided
MongoReader.<T> TfindOne
(Query query, Class<T> targetClass)
Map the results of an ad-hoc query on the default
MongoDB collection to a single instance of an object of the
specified type.<T> TfindOne
(Query query, Class<T> targetClass,
MongoReader<T> reader) Map the results of an
ad-hoc query on the default MongoDB collection to a single
instance of an object of the specified type.<T> TfindOne
(String collectionName, Query query,
Class<T> targetClass) Map the results of an
ad-hoc query on the specified collection to a single instance of
an object of the specified type.<T> TfindOne
(String collectionName, Query query,
Class<T> targetClass, MongoReader<T> reader)
Map the results of an ad-hoc query on the specified
collection to a single instance of an object of the specified
type.<T> List<T>find (Query query, Class<T>
targetClass) Map the results of an ad-hoc query on the
default MongoDB collection to a List of the specified type.<T> List<T>find (Query query, Class<T>
targetClass, MongoReader<T> reader) Map the
results of an ad-hoc query on the default MongoDB collection to a
List of the specified type.<T> List<T>find (String collectionName,
Query query, Class<T> targetClass) Map the
results of an ad-hoc query on the specified collection to a List
of the specified type.<T> List<T>find (String collectionName,
Query query, Class<T> targetClass, CursorPreparer preparer)
Map the results of an ad-hoc query on the specified
collection to a List of the specified type.<T> List<T>find (String collectionName,
Query query, Class<T> targetClass, MongoReader<T>
reader) Map the results of an ad-hoc query on the
specified collection to a List of the specified type.<T> TfindAndRemove (Query query,
Class<T> targetClass) Map the results of an
ad-hoc query on the default MongoDB collection to a single
instance of an object of the specified type. The first document
that matches the query is returned and also removed from the
collection in the database.<T> TfindAndRemove (Query query,
Class<T> targetClass, MongoReader<T> reader)
Map the results of an ad-hoc query on the default
MongoDB collection to a single instance of an object of the
specified type. The first document that matches the query is
returned and also removed from the collection in the
database.<T> TfindAndRemove (String
collectionName, Query query, Class<T> targetClass)
Map the results of an ad-hoc query on the specified
collection to a single instance of an object of the specified
type. The first document that matches the query is returned and
also removed from the collection in the database.<T> TfindAndRemove (String
collectionName, Query query, Class<T> targetClass,
MongoReader<T> reader) Map the results of an
ad-hoc query on the specified collection to a single instance of
an object of the specified type. The first document that matches
the query is returned and also removed from the collection in the
database.The MongoReader can be usedReading using MongoWriterThe MongoReader interface allows you to have lower level control
over the mapping of an DBObject into a Java object. This is similar to
the role of RowMapper in JdbcTemplate. The MongoReader interface
is/**
* A MongoWriter is responsible for converting a native MongoDB DBObject to an object of type T.
*
* @param <T> the type of the object to convert from a DBObject
*/
public interface MongoReader<T> {
/**
* Ready from the native MongoDB DBObject representation to an instance of the class T.
* The given type has to be the starting point for marshalling the {@link DBObject}
* into it. So in case there's no real valid data inside {@link DBObject} for the
* given type, just return an empty instance of the given type.
*
* @param clazz the type of the return value
* @param dbo theDBObject
* @return the converted object
*/
<S extends T> S read(Class<S> clazz, DBObject dbo);
}GeoSpatial QueriesMongoDB supports GeoSpatial queries through the use of operators
such as $near, $within, and
$nearSphere. Methods specific to geospatial queries
are available on the Criteria class. There are
also a few shape classes, Box,
Circle, and Point that are
used in conjunction with geospatial related Criteria methods.To understand how to perform GeoSpatial queries we will use the
following Venue class taken from the integration tests.which relies on
using the rich MappingMongoConverter.@Document(collection="newyork")
public class Venue {
@Id
private String id;
private String name;
private double[] location;
@PersistenceConstructor
Venue(String name, double[] location) {
super();
this.name = name;
this.location = location;
}
public Venue(String name, double x, double y) {
super();
this.name = name;
this.location = new double[] { x, y };
}
public String getName() {
return name;
}
public double[] getLocation() {
return location;
}
@Override
public String toString() {
return "Venue [id=" + id + ", name=" + name + ", location="
+ Arrays.toString(location) + "]";
}
}To find locations within a circle, the following query can be
used.Circle circle = new Circle(-73.99171, 40.738868, 0.01);
List<Venue> venues =
template.find(new Query(Criteria.where("location").withinCenter(circle)), Venue.class);To find venues within a circle using Spherical coordinates the
following query can be usedCircle circle = new Circle(-73.99171, 40.738868, 0.003712240453784);
List<Venue> venues =
template.find(new Query(Criteria.where("location").withinCenterSphere(circle)), Venue.class);To find venues within a Box the following query can be used//lower-left then upper-right
Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404));
List<Venue> venues =
template.find(new Query(Criteria.where("location").withinBox(box)), Venue.class);To find venues near a Point, the following query can be
usedPoint point = new Point(-73.99171, 40.738868);
List<Venue> venues =
template.find(new Query(Criteria.where("location").near(point).maxDistance(0.01)), Venue.class);To find venues near a Point using Spherical coordines the
following query can be usedPoint point = new Point(-73.99171, 40.738868);
List<Venue> venues =
template.find(new Query(
Criteria.where("location").nearSphere(point).maxDistance(0.003712240453784)),
Venue.class);
Support for the GeoNear command will be provided in the RC
release.Index and Collection managmentMongoTemplate provides a few methods for managing indexes and
collections.Methods for creating an IndexWe can create an index on a collection to improve query
performance.Creating an index using the MongoTemplatemongoTemplate.ensureIndex("MyCollection", new Index().on("name",Order.ASCENDING)); voidensureIndex
(IndexDefinition indexDefintion)
Ensure that an index for the provided IndexDefinition exists for
the default collection.voidensureIndex
(String collectionName, IndexDefinition
indexSpecification) Ensure that an index for the
provided IndexDefinition exists.You can create both standard indexes and geospatial indexes using
the classes IndexDefinition and
GeoSpatialIndex respectfully. For example, given
the Venue class defined in a previous section, you would declare a
geospatial query as shown belowmongoTemplate.ensureIndex(new GeospatialIndex("location"));Methods for working with a CollectionIt's time to look at some code examples showing how to use the
MongoTemplate. First we look at creating our
first collection.Working with collections using the MongoTemplateDBCollection collection = null;
if (!mongoTemplate.getCollectionNames().contains("MyNewCollection")) {
collection = mongoTemplate.createCollection("MyNewCollection");
}
mongoTemplate.dropCollection("MyNewCollection"); Set<String>getCollectionNames () A
set of collection names.booleancollectionExists (String
collectionName) Check to see if a collection with a
given name exists.DBCollectioncreateCollection (String
collectionName) Create an uncapped collection with the
provided name.DBCollectioncreateCollection (String
collectionName, CollectionOptions collectionOptions)
Create a collect with the provided name and options.voiddropCollection
(String collectionName) Drop the
collection with the given name.DBCollectiongetCollection (String
collectionName) Get a collection by name, creating it
if it doesn't exist.DBCollectiongetDefaultCollection ()
The default collection used by this template.StringgetDefaultCollectionName () The default collection name used by this
template.Executing CommandsYou can also get at the Mongo driver's collection.command( ) method
using the executeCommand methods on MongoTemplate. These will also perform
exception translation into Spring's Data Access Exception
hierarchy.Methods for executing commandsCommandResultexecuteCommand (DBObject command)
Execute a MongoDB command.CommandResultexecuteCommand (String
jsonCommand) Execute the a MongoDB command expressed as
a JSON string.Lifecycle EventsBuilt into the MongoDB mapping framework are several
org.springframework.context.ApplicationEvent events
that your application can respond to by registering special beans in the
ApplicationContext. By being based off Spring's
ApplicationContext event infastructure this enables other products, such
as Spring Integration, to easily receive these events as they are a well
known eventing mechanism in Spring based applications.To intercept an object before it goes through the conversion process
(which turns your domain object into a
com.mongodb.DBObject), you'd register a subclass of
org.springframework.data.document.mongodb.mapping.event.AbstractMappingEventListener
that overrides the onBeforeConvert method. When the event is
dispatched, your listener will be called and passed the domain object
before it goes into the converter.
public class BeforeConvertListener<BeforeConvertEvent, Person> extends AbstractMappingEventListener {
@Override
public void onBeforeConvert(Person p) {
... does some auditing manipulation, set timestamps, whatever ...
}
}
To intercept an object before it goes into the database, you'd
register a subclass of
org.springframework.data.document.mongodb.mapping.event.AbstractMappingEventListener
that overrides the onBeforeSave method. When the event is
dispatched, your listener will be called and passed the domain object and
the converted com.mongodb.DBObject.
public class BeforeSaveListener<BeforeSaveEvent, Person> extends AbstractMappingEventListener {
@Override
public void onBeforeSave(Person p, DBObject dbo) {
... change values, delete them, whatever ...
}
}
Simply declaring these beans in your Spring ApplicationContext will
cause them to be invoked whenever the event is dispatched.The list of callback methods that are present in
AbstractMappingEventListener areonBeforeConvert - called in
MongoTemplate insert, insertList and save operations before the object
is converted to a DBObject using a MongoConveter.onBeforeSave - called in MongoTemplate
insert, insertList and save operations before
inserting/saving the DBObject in the database.onAfterSave - called in MongoTemplate
insert, insertList and save operations after
inserting/saving the DBObject in the database.onAfterLoad - called in MongoTempnlate
find, findAndRemove, findOne and getCollection methods after the
DBObject is retrieved from the database.onAfterConvert - called in
MongoTempnlate find, findAndRemove, findOne and getCollection methods
after the DBObject retrieved from the database was converted to a
POJO.Exception TranslationThe Spring framework provides exception translation for a wide
variety of database and mapping technologies. This has traditionally been
for JDBC and JPA. The Spring support for Mongo extends this feature to the
MongoDB Database by providing an implementation of the
org.springframework.dao.support.PersistenceExceptionTranslator
interface.The motivation behind mapping to Spring's consistent
data access exception hierarchy is that you are then able to write
portable and descriptive exception handling code without resorting to
coding against MongoDB error
codes. All of Spring's data access exceptions are inherited from
the root DataAccessException class so you can be
sure that you will be able to catch all database related exception within
a single try-catch block. Note, that not all exceptions thrown by the
MongoDB driver inherit from the MongoException class. The inner exception
and message are preserved so no information is lost.Some of the mappings performed by the MongoExceptionTranslator are:
com.mongodb.Network to DataAccessResourceFailureException and
MongoException error codes 1003, 12001, 12010, 12011, 12012 to
InvalidDataAccessApiUsageException. Look into the implementation for more
details on the mapping.Execution CallbackOne common design feature of all Spring template classes is that all
functionality is routed into one of the templates execute callback
methods. This helps ensure that exceptions and any resource management
that maybe required are performed consistency. While this was of much
greater need in the case of JDBC and JMS than with MongoDB, it still
offers a single spot for exception translation and logging to occur. As
such, using thexe execute callback is the preferred way to access the
Mongo driver's DB and Collection objects to perform uncommon operations
that were not exposed as methods on
MongoTemplate.Here is a list of execute callback methods.<T> Texecute
(CollectionCallback<T> action)
Executes the given CollectionCallback on the default
collection.<T> Texecute
(String collectionName,
CollectionCallback<T> action) Executes the given
CollectionCallback on the collection of the given name.update using
the $addToSet update modifier<T> Texecute
(DbCallback<T> action)
Executes a DbCallback translating any exceptions as
necessary.<T> TexecuteInSession (DbCallback<T> action) Executes the given
DbCallback within the same connection to the database so as to
ensure consistency in a write heavy environment where you may read
the data that you wrote.Here is an example that uses the CollectionCallback to return
information about an index. boolean hasIndex = template.execute("geolocation", new CollectionCallback<Boolean>() {
public Boolean doInCollection(DBCollection collection) throws MongoException, DataAccessException {
List<DBObject> indexes = collection.getIndexInfo();
for (DBObject dbo : indexes) {
if ("location_2d".equals(dbo.get("name"))) {
return true;
}
}
return false;
}
});