MongoDB support The 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 sets MongoTemplate 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 hierarchy Feature Rich Object Mapping integrated with Spring's Conversion Service Annotation based mapping metadata but extensible to support other metadata formats Persistence and mapping lifecycle events Java based Query, Criteria, and Update DSLs Automatic 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 MongoDB Log4j log appender GeoSpatial integration For 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 Started Spring 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/mongod To 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 have log4j.category.org.springframework.data.document.mongodb=DEBUG log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n Create a simple Person class to persist package 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 run package 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 output 10: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 of You 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 object
Required 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.jar commons-logging-1.1.1.jar mongo-java-driver-2.5.3.jar spring-aop-3.0.5.RELEASE.jar spring-asm-3.0.5.RELEASE.jar spring-beans-3.0.5.RELEASE.jar spring-context-3I.0.5.RELEASE.jar spring-core-3.0.5.RELEASE.jar spring-expression-3.0.5.RELEASE.jar
Examples Repository There 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 Spring One 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 metadata An 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 metadata While 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 metadata As 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 metadata The 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 MongoTemplate The 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 MongoTemplate You 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 are MongoTemplate (Mongo mongo, String databaseName) - takes the default database name to operate against MongoTemplate (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 SimpleMongoConverter You 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 Policy When 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.
WriteConcern You 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 MongoConverter The 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 Documents MongoTemplate 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 Person public 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 = : 0 There 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 functionality The 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 layer Mongo 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 documents There 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 MongoTemplate import 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. void save (Object objectToSave) Save the object to the default collection. void save (String collectionName, Object objectToSave) Save the object to the specified collection. <T> void save (T objectToSave, MongoWriter<T> writer) Save the object into the default collection using the provided writer. <T> void save (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 below void insert (Object objectToSave) Insert the object to the default collection. void insert (String collectionName, Object objectToSave) Insert the object to the specified collection. <T> void insert (T objectToSave, MongoWriter<T> writer) Insert the object into the default collection using the provided writer. <T> void insert (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 MongoWriter The 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 batch The MongoDB driver supports inserting a collection of documents in one operation. The methods in the MongoOperations interface that support this functionality are listed below void insertList (List<? extends Object> listToSave) Insert a list of objects into the default collection in a single batch write to the database. void insertList (String collectionName, List<? extends Object> listToSave) Insert a list of objects into the specified collection in a single batch write to the database. <T> void insertList (List<? extends T> listToSave, MongoWriter<T> writer) Insert the object into the default collection using the provided writer. <T> void insertList(String collectionName, List<? extends T> listToSave, MongoWriter<T> writer) Insert a list of objects into the specified collection using the provided MongoWriter instance
Updating documents in a collection For 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 MongoTemplate import 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 documents WriteResult updateFirst (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. WriteResult updateFirst (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. WriteResult updateMulti (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. WriteResult updateMulti (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 class Update addToSet (String key, Object value) Update using the $addToSet update modifier Update inc (String key, Number inc) Update using the $inc update modifier Update pop (String key, Update.Position pos) Update using the $pop update modifier Update pull (String key, Object value) Update using the $pull update modifier Update pullAll (String key, Object[] values) Update using the $pullAll update modifier Update push (String key, Object value) Update using the $push update modifier Update pushAll (String key, Object[] values) Update using the $pushAll update modifier Update rename (String oldName, String newName) Update using the $rename update modifier Update set (String key, Object value) Update using the $set update modifier Update unset (String key) Update using the $unset update modifier
Methods for removing documents You can use several overloaded methods to remove an object from the database. void remove (Object object) Remove the given object from the collection by Id void remove (Query query) Remove all documents from the default collection that match the provided query document criteria. void remove (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 uqery
Querying Documents You 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 collection We 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 MongoTemplate import 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 class Criteria all (Object o)Creates a criterion using the $all operator Criteria elemMatch (Criteria c) Creates a criterion using the $elemMatch operator Criteria exists (boolean b) Creates a criterion using the $exists operator Criteria gt (Object o)Creates a criterion using the $gt operator Criteria gte (Object o)Creates a criterion using the $gte operator Criteria in (Object... o) Creates a criterion using the $in operator Criteria is (Object o)Creates a criterion using the $is operator Criteria lt (Object o)Creates a criterion using the $lt operator Criteria lte (Object o)Creates a criterion using the $lte operator Criteria mod (Number value, Number remainder)Creates a criterion using the $mod operator Criteria nin (Object... o) Creates a criterion using the $nin operator Criteria not ()Creates a criterion using the $not meta operator which affects the clause directly following Criteria regex (String re) Creates a criterion using a $regex Criteria size (int s)Creates a criterion using the $size operator Criteria type (int t)Creates a criterion using the $type operator Criteria and (String key) Adds a chained Criteria with the specified key to the current Criteria and retuns the newly created one
There 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. Criteria withinCenter (Circle circle)Creates a geospatial criterion using $within $center operators Criteria withinCenterSphere (Circle circle) Creates a geospatial criterion using $within $center operators. This is only available for Mongo 1.7 and higher. Criteria withinBox (Box box)Creates a geospatial criterion using a $within $box operation Criteria near (Point point)Creates a geospatial criterion using a $near operation Criteria nearSphere (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 class Query addCriteria (Criteria criteria) used to add additional criteria to the query void or (List<Query> queries) Creates an or query using the $or operator for all of the provided queries Field fields () used to define fields to be included in the query results Query limit (int limit) used to limit the size of the returned results to the provided limit (used for paging) Query skip (int skip) used to skip the provided number of documents in the results (used for paging) Sort sort () used to provide sort definition for the results
Methods 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> T findOne (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> T findOne (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> T findOne (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> T findOne (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> T findAndRemove (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> T findAndRemove (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> T findAndRemove (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> T findAndRemove (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 used
Reading using MongoWriter The 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 Queries MongoDB 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 used Circle 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 used Point 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 used Point 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 managment MongoTemplate provides a few methods for managing indexes and collections.
Methods for creating an Index We can create an index on a collection to improve query performance. Creating an index using the MongoTemplate mongoTemplate.ensureIndex("MyCollection", new Index().on("name",Order.ASCENDING)); void ensureIndex (IndexDefinition indexDefintion) Ensure that an index for the provided IndexDefinition exists for the default collection. void ensureIndex (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 below mongoTemplate.ensureIndex(new GeospatialIndex("location"));
Methods for working with a Collection It'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 MongoTemplate DBCollection collection = null; if (!mongoTemplate.getCollectionNames().contains("MyNewCollection")) { collection = mongoTemplate.createCollection("MyNewCollection"); } mongoTemplate.dropCollection("MyNewCollection"); Set<String> getCollectionNames () A set of collection names. boolean collectionExists (String collectionName) Check to see if a collection with a given name exists. DBCollection createCollection (String collectionName) Create an uncapped collection with the provided name. DBCollection createCollection (String collectionName, CollectionOptions collectionOptions) Create a collect with the provided name and options. void dropCollection (String collectionName) Drop the collection with the given name. DBCollection getCollection (String collectionName) Get a collection by name, creating it if it doesn't exist. DBCollection getDefaultCollection () The default collection used by this template. String getDefaultCollectionName () The default collection name used by this template.
Executing Commands You 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 commands CommandResult executeCommand (DBObject command) Execute a MongoDB command. CommandResult executeCommand (String jsonCommand) Execute the a MongoDB command expressed as a JSON string.
Lifecycle Events Built 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 are onBeforeConvert - 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 Translation The 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 Callback One 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> T execute (CollectionCallback<T> action) Executes the given CollectionCallback on the default collection. <T> T execute (String collectionName, CollectionCallback<T> action) Executes the given CollectionCallback on the collection of the given name.update using the $addToSet update modifier <T> T execute (DbCallback<T> action) Executes a DbCallback translating any exceptions as necessary. <T> T executeInSession (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; } });