You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2227 lines
90 KiB
2227 lines
90 KiB
<?xml version="1.0" encoding="UTF-8"?> |
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> |
|
<chapter id="mongo.core"> |
|
<title>MongoDB support</title> |
|
|
|
<para>The MongoDB support contains a wide range of features which are |
|
summarized below.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>Spring configuration support using Java based @Configuration |
|
classes or an XML namespace for a Mongo driver instance and replica |
|
sets</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>MongoTemplate helper class that increases productivity performing |
|
common Mongo operations. Includes integrated object mapping between |
|
documents and POJOs.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Exception translation into Spring's portable Data Access Exception |
|
hierarchy</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Feature Rich Object Mapping integrated with Spring's Conversion |
|
Service</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Annotation based mapping metadata but extensible to support other |
|
metadata formats</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Persistence and mapping lifecycle events</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Java based Query, Criteria, and Update DSLs</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Automatic implementatin of Repository interfaces including support |
|
for custom finder methods.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>QueryDSL integration to support type-safe queries.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Cross-store persistance - support for JPA Entities with fields |
|
transparently persisted/retrieved using MongoDB</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Log4j log appender</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>GeoSpatial integration</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>For most tasks you will find yourself using |
|
<classname>MongoTemplate</classname> 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 |
|
<literal>org.mongo.DB</literal> 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.</para> |
|
|
|
<section id="mongodb-getting-started"> |
|
<title>Getting Started</title> |
|
|
|
<para>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 <ulink |
|
url="http://www.springsource.com/developer/sts">STS</ulink>.</para> |
|
|
|
<para>First you need to set up a running Mongodb server. Refer to the |
|
<ulink url="http://www.mongodb.org/display/DOCS/Quickstart">Mongodb Quick |
|
Start guide</ulink> for an explanation on how to startup a Mongo instance. |
|
Once installed starting Mongo is typically a matter of executing the |
|
following command: <literal>MONGO_HOME/bin/mongod</literal></para> |
|
|
|
<para>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.</para> |
|
|
|
<para>Then add the following to pom.xml dependencies section.</para> |
|
|
|
<programlisting lang="" language="xml"><dependencies> |
|
|
|
<!-- other dependency elements omitted --> |
|
|
|
<dependency> |
|
<groupId>org.springframework.data</groupId> |
|
<artifactId>spring-data-mongodb</artifactId> |
|
<version>1.0.0.M3</version> |
|
</dependency> |
|
|
|
</dependencies> |
|
</programlisting> |
|
|
|
<para>Also change the version of Spring in the pom.xml to be</para> |
|
|
|
<programlisting lang="" language="xml"><spring.framework.version>3.0.5.RELEASE</spring.framework.version></programlisting> |
|
|
|
<para>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</para> |
|
|
|
<programlisting language="xml"><repositories> |
|
<repository> |
|
<id>spring-milestone</id> |
|
<name>Spring Maven MILESTONE Repository</name> |
|
<url>http://maven.springframework.org/milestone</url> |
|
</repository> |
|
</repositories></programlisting> |
|
|
|
<para>The repository is also <ulink |
|
url="http://shrub.appspot.com/maven.springframework.org/milestone/org/springframework/data/">browseable |
|
here</ulink>.</para> |
|
|
|
<para>You may also want to set the logging level to DEBUG to see some |
|
additional information, edit the log4j.properties file to have</para> |
|
|
|
<programlisting>log4j.category.org.springframework.data.document.mongodb=DEBUG |
|
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n</programlisting> |
|
|
|
<para>Create a simple Person class to persist</para> |
|
|
|
<programlisting language="java">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 + "]"; |
|
} |
|
|
|
}</programlisting> |
|
|
|
<para>And a main application to run</para> |
|
|
|
<programlisting language="java">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"); |
|
} |
|
}</programlisting> |
|
|
|
<para>This will produce the following output</para> |
|
|
|
<programlisting>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]</programlisting> |
|
|
|
<para>Even in this simple example, there are few things to take notice |
|
of</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>You can instantiate the central helper class of Spring Mongo, |
|
<link linkend="mongo-template">MongoTemplate</link>, using the |
|
standard <classname>com.mongodb.Mongo</classname> object and the name |
|
of the database to use.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>The mapper works against standard POJO objects without the need |
|
for any additional metadata (though you can optionally provide that |
|
information. See <link linkend="mongo.mapping">here</link>.).</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Conventions are used for handling the id field, converting it to |
|
be a ObjectId when stored in the database.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Mapping conventions can use field access. Notice the Person |
|
class has only getters.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>If the constructor argument names match the field names of the |
|
stored document, they will be used to instantiate the object</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<section id="mongodb-required-jars"> |
|
|
|
|
|
<title>Required Jars</title> |
|
|
|
The following jars are required to use Spring Data Mongo |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>spring-data-mongodb-1.0.0.M3.jar</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>spring-data-commons-1.1.0.M1.jar</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
In addition to the above listed Spring Data jars you need to provide the following dependencies: |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>aopalliance-1.0.0.jar</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>commons-logging-1.1.1.jar</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>mongo-java-driver-2.5.3.jar</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>spring-aop-3.0.5.RELEASE.jar</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>spring-asm-3.0.5.RELEASE.jar</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>spring-beans-3.0.5.RELEASE.jar</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>spring-context-3I.0.5.RELEASE.jar</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>spring-core-3.0.5.RELEASE.jar</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>spring-expression-3.0.5.RELEASE.jar</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
|
|
</section> |
|
|
|
<section> |
|
<title>Migrating from M2 to M3</title> |
|
|
|
<para>There were several API changes introduced in the M3 release. To |
|
upgrade from M2 to M3 you will need to make. For a full listing of API |
|
changes please refer to this <ulink |
|
url="http://static.springsource.org/spring-data/data-document/docs/jdiff-mongo-m2-m3/mongo-report/">JDiff |
|
Report</ulink>.</para> |
|
|
|
<para>The major changes are with respect to MongoTemplate</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>Constructors have changed on |
|
<classname>MongoTemplate</classname>. <literal>MongoTemplate(Mongo, |
|
String, String)</literal> and <literal>MongoTemplate(Mongo, String, |
|
String, MongoConverter)</literal> were removed. |
|
<literal>MongoTemplate(Mongo, String, UserCredentials), |
|
MongoTemplate(MongoDbFactory), MongoTemplate(MongoDbFactory, |
|
MongoConverter)</literal> were added. These changes will also effect |
|
usage of wiring up <classname>MongoTemplate</classname> in |
|
<bean/> XML defintions.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><classname>MongoTemplate</classname> no longer takes a default |
|
collection name. The collection name is now either specified when |
|
the method is invoked or inferred from the Java class, either the |
|
class name or via mapping metadata.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Reordered parameters in some |
|
<classname>MongoTemplate</classname> methods to make signatures more |
|
consistent across the board.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Removed <classname>MongoTemplate</classname> methods that use |
|
<interfacename>MongoReader</interfacename> and |
|
<interfacename>MongoWriter</interfacename>. As an alternative |
|
register a Spring converter with the MappingMongoConverter. See |
|
<link linkend="mapping-explicit-converters">here</link> for |
|
details.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Added <literal>findById</literal> methods to |
|
<classname>MongoTemplate.</classname></para> |
|
</listitem> |
|
</itemizedlist> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<title>Examples Repository</title> |
|
|
|
<para>There is an <ulink |
|
url="https://github.com/SpringSource/spring-data-document-examples">github |
|
repository with several examples</ulink> that you can download and play |
|
around with to get a feel for how the library works.</para> |
|
</section> |
|
|
|
<section id="mongodb-connectors"> |
|
<title>Connecting to MongoDB with Spring</title> |
|
|
|
<para>One of the first tasks when using MongoDB and Spring is to create a |
|
<classname>com.mongodb.Mongo</classname> 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. |
|
<note> |
|
<para>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 <ulink |
|
url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/new-in-3.html#new-java-configuration" |
|
userlevel="">here </ulink> as well as the detailed documentation<ulink |
|
url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java-instantiating-container"> |
|
here</ulink>.</para> |
|
</note></para> |
|
|
|
<section> |
|
<title>Registering a Mongo instance using Java based metadata</title> |
|
|
|
<para>An example of using Java based bean metadata to register an |
|
instance of a <classname>com.mongodb.Mongo</classname> is shown below |
|
<example> |
|
<title>Registering a com.mongodb.Mongo object using Java based bean |
|
metadata</title> |
|
|
|
<programlisting language="java">@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"); |
|
} |
|
} </programlisting> |
|
</example></para> |
|
|
|
<para>This approach allows you to use the standard |
|
<classname>com.mongodb.Mongo</classname> 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.</para> |
|
|
|
<para>An alternative is to register an instance of |
|
<classname>com.mongodb.Mongo</classname> instance with the container |
|
using Spring's<interfacename> MongoFactoryBean</interfacename>. As |
|
compared to instantiating a <classname>com.mongodb.Mongo</classname> |
|
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 |
|
<classname>DataAccessException</classname> hierarchy for data access |
|
classes annoated with the <literal>@Repository</literal> annotation. |
|
This hierarchy and use of <literal>@Repository</literal> is described in |
|
<ulink |
|
url="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/dao.html">Spring's |
|
DAO support features</ulink>.</para> |
|
|
|
<para>An example of a Java based bean metadata that supports exception |
|
translation on <classname>@Repository</classname> annotated classes is |
|
shown below:</para> |
|
|
|
<example> |
|
<title>Registering a com.mongodb.Mongo object using Spring's |
|
MongoFactoryBean and enabling Spring's exception translation |
|
support</title> |
|
|
|
<programlisting language="java">@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; |
|
} |
|
} |
|
</programlisting> |
|
|
|
<para>To access the <classname>com.mongodb.Mongo</classname> object |
|
created by the <classname>MongoFactoryBean</classname> in other |
|
<literal>@Configuration</literal> or your own classes, use a |
|
"<literal>private @Autowired Mongo mongo;</literal>" field.</para> |
|
</example> |
|
</section> |
|
|
|
<section> |
|
<title>Registering a Mongo instance using XML based metadata</title> |
|
|
|
<para>While you can use Spring's traditional |
|
<literal><beans/></literal> XML namespace to register an instance |
|
of <classname>com.mongodb.Mongo</classname> 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.</para> |
|
|
|
<para>To use the Mongo namespace elements you will need to reference the |
|
Mongo schema:</para> |
|
|
|
<example> |
|
<title>XML schema to configure MongoDB</title> |
|
|
|
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?> |
|
<beans xmlns="http://www.springframework.org/schema/beans" |
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
xmlns: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 |
|
<emphasis role="bold">http://www.springframework.org/schema/data/mongo |
|
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd</emphasis> |
|
http://www.springframework.org/schema/beans |
|
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> |
|
|
|
<!-- Default bean name is 'mongo' --> |
|
<emphasis role="bold"><mongo:mongo host="localhost" port="27017"/></emphasis> |
|
|
|
</beans> |
|
</programlisting> |
|
</example> |
|
|
|
<para>A more advanced configuration with MongoOptions is shown below |
|
(note these are not recommended values)</para> |
|
|
|
<example> |
|
<title>XML schema to configure a com.mongodb.Mongo object with |
|
MongoOptions</title> |
|
|
|
<programlisting language="xml"><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> |
|
</programlisting> |
|
</example> |
|
|
|
<para>A configuration using replica sets is shown below. <example> |
|
<title>XML schema to configure com.mongodb.Mongo object with Replica |
|
Sets</title> |
|
|
|
<programlisting language="xml"><mongo:mongo id="replicaSetMongo" replica-set="127.0.0.1:27017,localhost:27018"/> </programlisting> |
|
</example></para> |
|
</section> |
|
|
|
<section> |
|
<title>The MongoDbFactory interface</title> |
|
|
|
<para>While com.mongodb.Mongo is the entry point to the MongoDB driver |
|
API, connecting to a specific MongoDB database instance requires |
|
additional information such as the database name and an optional |
|
username and password. With that information you can obtain a |
|
com.mongodb.DB object and access all the functionality of a specific |
|
MongoDB database instance. Spring provides the |
|
<classname>org.springframework.data.document.mongodb.MongoDbFactory</classname> |
|
interface shown below to bootstrap connectivity to the database.</para> |
|
|
|
<programlisting language="java">public interface MongoDbFactory { |
|
|
|
DB getDb() throws DataAccessException; |
|
|
|
DB getDb(String dbName) throws DataAccessException; |
|
|
|
}</programlisting> |
|
|
|
<para>The following sections show how you can use the contiainer with |
|
either Java or the XML based metadata to configure an instance of the |
|
<classname>MongoDbFactory</classname> interface. In turn, you can use |
|
the <classname>MongoDbFactory</classname> instance to configure |
|
MongoTemplate.</para> |
|
|
|
<para>The class |
|
<classname>org.springframework.data.document.mongodb.SimpleMongoDbFactory</classname> |
|
provides implements the MongoDbFactory interface and is created with a |
|
standard <classname>com.mongodb.Mongo</classname> instance, the database |
|
name and an optional |
|
<classname>org.springframework.data.authentication.UserCredentials</classname> |
|
constructor argument.</para> |
|
|
|
<para>Instead of using the IoC container to create an instance of |
|
MongoTemplate, you can just use them in standard Java code as shown |
|
below.</para> |
|
|
|
<programlisting language="java">public class MongoApp { |
|
|
|
private static final Log log = LogFactory.getLog(MongoApp.class); |
|
|
|
public static void main(String[] args) throws Exception { |
|
|
|
MongoOperations mongoOps = new MongoTemplate(<emphasis role="bold">new SimpleMongoDbFactory(new Mongo(), "database")</emphasis>); |
|
|
|
mongoOps.insert(new Person("Joe", 34)); |
|
|
|
log.info(mongoOps.findOne(new Query(where("name").is("Joe")), Person.class)); |
|
|
|
mongoOps.dropCollection("person"); |
|
} |
|
}</programlisting> |
|
|
|
<para>The code in bold highlights the use of SimpleMongoDbFactory and is |
|
the only difference between the listing shown in the <link lang="" |
|
linkend="mongodb-getting-started" os="">getting started |
|
section</link>.</para> |
|
</section> |
|
|
|
<section> |
|
<title>Registering a MongoDbFactory instance using Java based |
|
metadata</title> |
|
|
|
<para>To register a MongoDbFactory instance with the container, you |
|
write code much like what was highlighted in the previous code listing. |
|
A simple example is shown below</para> |
|
|
|
<programlisting language="java">@Configuration |
|
public class MongoConfiguration { |
|
|
|
public @Bean MongoDbFactory mongoDbFactory() throws Exception { |
|
return new SimpleMongoDbFactory(new Mongo(), "database"); |
|
} |
|
|
|
}</programlisting> |
|
|
|
<para>To define the username and password create an instance of |
|
<classname>org.springframework.data.authentication.UserCredentials</classname> |
|
and pass it into the constructor as shown below. This listing also shows |
|
using <classname>MongoDbFactory</classname> register an instance of |
|
MongoTemplate with the container.</para> |
|
|
|
<programlisting language="java">@Configuration |
|
public class MongoConfiguration { |
|
|
|
public @Bean MongoDbFactory mongoDbFactory() throws Exception { |
|
UserCredentials userCredentials = new UserCredentials("joe", "secret"); |
|
return new SimpleMongoDbFactory(new Mongo(), "database", userCredentials); |
|
} |
|
|
|
public @Bean MongoTemplate mongoTemplate() throws Exception { |
|
return new MongoTemplate(mongoDbFactory()); |
|
} |
|
} |
|
</programlisting> |
|
|
|
<para></para> |
|
</section> |
|
|
|
<section> |
|
<title>Registering a MongoDbFactory instance using XML based |
|
metadata</title> |
|
|
|
<para>The mongo namespace provides a convient way to create a |
|
<classname>SimpleMongoDbFactory</classname> as compared to using |
|
the<literal><beans/></literal> namespace. Simple usage is shown |
|
below</para> |
|
|
|
<programlisting language="xml"><mongo:db-factory dbname="database"></programlisting> |
|
|
|
<para>In the above example a <classname>com.mongodb.Mongo</classname> |
|
instance is created using the default host and port number. The |
|
<classname>SimpleMongoDbFactory</classname> registered with the |
|
container is identified by the id 'mongoDbFactory' unless a value for |
|
the id attribute is specified.</para> |
|
|
|
<para>You can also provide the host and port for the underlying |
|
com.mongodb.Mongo instance as shown below, in addition to username and |
|
password for the database.</para> |
|
|
|
<programlisting language="xml"><mongo:db-factory id="anotherMongoDbFactory" |
|
host="localhost" |
|
port="27017" |
|
dbname="database" |
|
username="joe" |
|
password="secret"/></programlisting> |
|
|
|
<para>If you need to configure additional options on the |
|
<classname>com.mongodb.Mongo</classname> instance that is used to create |
|
a <classname>SimpleMongoDbFactory</classname> you can refer to an |
|
existing bean using the <literal>mongo-ref</literal> attribute as shown |
|
below. To show another common usage pattern, this listing show the use |
|
of a property placeholder to parameterise the configuration and creating |
|
<classname>MongoTemplate</classname>.</para> |
|
|
|
<programlisting language="xml"><context:property-placeholder location="classpath:/com/myapp/mongodb/config/mongo.properties"/> |
|
|
|
<mongo:mongo host="${mongo.host}" port="${mongo.port}"> |
|
<mongo:options |
|
connections-per-host="${mongo.connectionsPerHost}" |
|
threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}" |
|
connect-timeout="${mongo.connectTimeout}" |
|
max-wait-time="${mongo.maxWaitTime}" |
|
auto-connect-retry="${mongo.autoConnectRetry}" |
|
socket-keep-alive="${mongo.socketKeepAlive}" |
|
socket-timeout="${mongo.socketTimeout}" |
|
slave-ok="${mongo.slaveOk}" |
|
write-number="1" |
|
write-timeout="0" |
|
write-fsync="true"/> |
|
</mongo:mongo> |
|
|
|
<mongo:db-factory dbname="database" mongo-ref="mongo"/> |
|
|
|
<bean id="anotherMongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate"> |
|
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> |
|
</bean></programlisting> |
|
|
|
<para></para> |
|
</section> |
|
</section> |
|
|
|
<section id="mongo-template"> |
|
<title>Introduction to MongoTemplate</title> |
|
|
|
<para>The class <classname>MongoTemplate</classname>, located in the |
|
package <literal>org.springframework.data.document.mongodb</literal>, is |
|
the central class of the Spring's MongoDB support providng a rich feature |
|
set to interact with the database. The template offers convenience |
|
operations to create, update, delete and query for MongoDB documents and |
|
provides a mapping between your domain objects and MongoDB |
|
documents.</para> |
|
|
|
<note> |
|
<para>Once configured, <classname>MongoTemplate</classname> is |
|
thread-safe and can be reused across multiple instances.</para> |
|
</note> |
|
|
|
<para>The mapping between Mongo documents and domain classes is done by |
|
delegating to an implementation of the interface |
|
<interfacename>MongoConverter</interfacename>. Spring provides two |
|
implementations, <classname>SimpleMappingConverter</classname> and |
|
<classname>MongoMappingConverter</classname>, but you can also write your |
|
own converter. Please refer to the section on MongoCoverters for more |
|
detailed information.</para> |
|
|
|
<para>The <classname>MongoTemplate</classname> class implements the |
|
interface <interfacename>MongoOperations</interfacename>. In as much as |
|
possible, the methods on <interfacename>MongoOperations</interfacename> |
|
are named after methods available on the MongoDB driver |
|
<classname>Collection</classname> object as as to make the API familiar to |
|
existing MongoDB developers who are used to the driver API. 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 <interfacename>MongoOperations</interfacename>. A |
|
major difference in between the two APIs is that MongOperations can be |
|
passed domain objects instead of <classname>DBObject</classname> and there |
|
are fluent APIs for <classname>Query</classname>, |
|
<classname>Criteria</classname>, and <classname>Update</classname> |
|
operations instead of populating a <classname>DBObject</classname> to |
|
specify the parameters for those operatiosn.</para> |
|
|
|
<note> |
|
<para>The preferred way to reference the operations on |
|
<classname>MongoTemplate</classname> instance is via its interface |
|
<interfacename>MongoOperations</interfacename>.</para> |
|
</note> |
|
|
|
<para>The default converter implementation used by |
|
<classname>MongoTemplate</classname> is MongoMappingConverter. While the |
|
<classname>MongoMappingConverter</classname> can make use of additional |
|
metadata to specify the mapping of objects to documents it is also capable |
|
of converting objects that contain no additonal metadata by using some |
|
conventions for the mapping of IDs and collection names. These conventions |
|
as well as the use of mapping annotations is explained in the <link |
|
linkend="mongo.mapping">Mapping chapter</link>.<note> |
|
<para>In the M2 release <classname>SimpleMappingConverter</classname>, |
|
was the default and this class is now deprecated as its functionality |
|
has been subsumed by the MongoMappingConverter.</para> |
|
</note></para> |
|
|
|
<para>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 <link |
|
linkend="mongo.exception">exception translation</link> for more |
|
information.</para> |
|
|
|
<para>While there are many convenience methods on |
|
<classname>MongoTemplate</classname> 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 to access underlying driver APIs. The |
|
execute callbacks will give you a reference to either a |
|
<classname>com.mongodb.Collection</classname> or a |
|
<classname>com.mongodb.DB</classname> object. Please see the section |
|
<ulink url="mongo.executioncallback">Execution Callbacks</ulink> for more |
|
information.</para> |
|
|
|
<para>Now let's look at a examples of how to work with the |
|
<classname>MongoTemplate</classname> in the context of the Spring |
|
container.</para> |
|
|
|
<section> |
|
<title>Instantiating MongoTemplate</title> |
|
|
|
<para>You can use Java to create and register an instance of |
|
MongoTemplate as shown below.</para> |
|
|
|
<example> |
|
<title>Registering a com.mongodb.Mongo object and enabling Spring's |
|
exception translation support</title> |
|
|
|
<programlisting language="java">@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"); |
|
} |
|
} |
|
</programlisting> |
|
</example> |
|
|
|
<para>There are several overloaded constructors of MongoTemplate. These |
|
are</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><emphasis role="bold">MongoTemplate </emphasis> |
|
<literal>(Mongo mongo, String databaseName)</literal> - takes the |
|
com.mongodb.Mongo object and the default database name to operate |
|
against.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">MongoTemplate </emphasis> |
|
<literal>(Mongo mongo, String databaseName, UserCredentials |
|
userCredentials) </literal> - adds the username and password for |
|
authenticating with the database.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">MongoTemplate</emphasis> |
|
<literal>(MongoDbFactory mongoDbFactory)</literal> - takes a |
|
MongoDbFactory object that encapsulated the com.mongodb.Mongo |
|
object, database name, and username and password.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">MongoTemplate </emphasis> |
|
<literal>(MongoDbFactory mongoDbFactory, MongoConverter |
|
mongoConverter) </literal> - adds a MongoConverter to use for |
|
mapping.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>You can also configure a MongoTemplate using Spring's XML |
|
<beans/> schema.</para> |
|
|
|
<programlisting language="java"> <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"/> |
|
</bean></programlisting> |
|
|
|
<para>Other optional properties that you might like to set when creating |
|
a <classname>MongoTemplate</classname> are the default |
|
<classname>WriteResultCheckingPolicy</classname>, |
|
<classname>WriteConcern</classname>, and <classname>SlaveOk</classname> |
|
write option.</para> |
|
|
|
<note> |
|
<para>The preferred way to reference the operations on |
|
<classname>MongoTemplate</classname> instance is via its interface |
|
<interfacename>MongoOperations</interfacename>.</para> |
|
</note> |
|
|
|
<section> |
|
<title>WriteResultChecking Policy</title> |
|
|
|
<para>When in development it is very handy to either log or throw an |
|
exception if the <classname>com.mongodb.WriteResult</classname> |
|
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 runs successfully but in fact the |
|
database was not modified according to your expectations. Set |
|
MongoTemplate's <property>WriteResultChecking</property> property to |
|
an enum with the following values, LOG, EXCEPTION, or NONE to either |
|
log the error, throw and exception or do nothing. The default is to |
|
use a <literal>WriteResultChecking</literal> value of NONE.</para> |
|
</section> |
|
|
|
<section> |
|
<title>WriteConcern</title> |
|
|
|
<para>You can set the <classname>com.mongodb.WriteConcern</classname> |
|
property that the <classname>MongoTemplate</classname> will use for |
|
write operations if it has not yet been specified via the driver at a |
|
higher level such as com.mongodb.Mongo. If MongoTemplate's |
|
<classname>WriteConcern</classname> property is not set it will |
|
default to the one set in the MongoDB driver's DB or Collection |
|
setting.</para> |
|
|
|
<note> |
|
<para>Setting the <classname>WriteConcern</classname> 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.</para> |
|
</note> |
|
</section> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<title>Saving, Updating, and Removing Documents</title> |
|
|
|
<para><classname>MongoTemplate</classname> provides a simple way for you |
|
to save, update, and delete your domain objects and map those objects to |
|
documents stored in MongoDB.</para> |
|
|
|
<para>Given a simple class such as Person</para> |
|
|
|
<programlisting language="java">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 + "]"; |
|
} |
|
|
|
} |
|
</programlisting> |
|
|
|
<para>You can save, update and delete the object as shown below.</para> |
|
|
|
<note> |
|
<para><interfacename>MongoOperations</interfacename> is the interface |
|
that <classname>MongoTemplate</classname> implements.</para> |
|
</note> |
|
|
|
<programlisting language="java">package org.spring.example; |
|
|
|
import static org.springframework.data.document.mongodb.query.Criteria.where; |
|
import static org.springframework.data.document.mongodb.query.Update.update; |
|
import static org.springframework.data.document.mongodb.query.Query.query; |
|
|
|
import java.util.List; |
|
|
|
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.SimpleMongoDbFactory; |
|
|
|
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 SimpleMongoDbFactory(new Mongo(), "database")); |
|
|
|
Person p = new Person("Joe", 34); |
|
|
|
// Insert is used to initially store the object into the database. |
|
mongoOps.insert(p); |
|
log.info("Insert: " + p); |
|
|
|
// Find |
|
p = mongoOps.findById(p.getId(), Person.class); |
|
log.info("Found: " + p); |
|
|
|
// Update |
|
mongoOps.updateFirst(query(where("name").is("Joe")), update("age", 35), Person.class); |
|
p = mongoOps.findOne(query(where("name").is("Joe")), Person.class); |
|
log.info("Updated: " + p); |
|
|
|
// Delete |
|
mongoOps.remove(p); |
|
|
|
// Check that deletion worked |
|
List<Person> people = mongoOps.findAll(Person.class); |
|
log.info("Number of people = : " + people.size()); |
|
|
|
|
|
mongoOps.dropCollection(Person.class); |
|
} |
|
} |
|
</programlisting> |
|
|
|
<para>This would produce the following log output (including debug |
|
messages from <classname>MongoTemplate</classname> itself)</para> |
|
|
|
<programlisting>DEBUG apping.MongoPersistentEntityIndexCreator: 80 - Analyzing class class org.spring.example.Person for index information. |
|
DEBUG work.data.document.mongodb.MongoTemplate: 632 - insert DBObject containing fields: [_class, age, name] in collection: person |
|
INFO org.spring.example.MongoApp: 30 - Insert: Person [id=4ddc6e784ce5b1eba3ceaf5c, name=Joe, age=34] |
|
DEBUG work.data.document.mongodb.MongoTemplate:1246 - findOne using query: { "_id" : { "$oid" : "4ddc6e784ce5b1eba3ceaf5c"}} in db.collection: database.person |
|
INFO org.spring.example.MongoApp: 34 - Found: Person [id=4ddc6e784ce5b1eba3ceaf5c, name=Joe, age=34] |
|
DEBUG work.data.document.mongodb.MongoTemplate: 778 - calling update using query: { "name" : "Joe"} and update: { "$set" : { "age" : 35}} in collection: person |
|
DEBUG work.data.document.mongodb.MongoTemplate:1246 - findOne using query: { "name" : "Joe"} in db.collection: database.person |
|
INFO org.spring.example.MongoApp: 39 - Updated: Person [id=4ddc6e784ce5b1eba3ceaf5c, name=Joe, age=35] |
|
DEBUG work.data.document.mongodb.MongoTemplate: 823 - remove using query: { "id" : "4ddc6e784ce5b1eba3ceaf5c"} in collection: person |
|
INFO org.spring.example.MongoApp: 46 - Number of people = : 0 |
|
DEBUG work.data.document.mongodb.MongoTemplate: 376 - Dropped collection [database.person]</programlisting> |
|
|
|
<para>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.</para> |
|
|
|
<note> |
|
<para>This example is meant to show the use of save, update and remove |
|
operations on MongoTemplate and not to show complex mapping |
|
functionality</para> |
|
</note> |
|
|
|
<para>The query stynax used in the example is explained in more detail in |
|
the section <link linkend="mongo.query">Querying Documents</link>.</para> |
|
|
|
<section> |
|
<title>How the '_id' field is handled in the mapping layer</title> |
|
|
|
<para>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 <classname>MongoMappingConverter</classname> there |
|
are certain rules that govern how properties from the Java class is |
|
mapped to this '_id' field.</para> |
|
|
|
<para>The following outlines what property will be mapped to the '_id' |
|
document field:</para> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para>A property or field annotated with |
|
<classname>@Id</classname> |
|
(<classname>org.springframework.data.annotation.Id</classname>) |
|
will be mapped to the '_id' field.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>A property or field without an annotation but named |
|
<classname>id</classname> will be mapped to the '_id' |
|
field.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
|
|
<para>The following outlines what type conversion, if any, will be done |
|
on the property mapped to the _id document field when using the |
|
<classname>MappingMongoConverter</classname>, the default for |
|
<classname>MongoTemplate</classname>.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>An id property or field declared as a String in the Java class |
|
will be converted to and stored as an ObjectId if possible using a |
|
Spring Converter<String, ObjectId>. Valid conversion rules are |
|
delegated to the Mongo Java driver. If it cannot be converted to an |
|
ObjectId, then the value will be stored as a string in the |
|
database.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>An id property or field declared as BigInteger in the Java |
|
class will be converted to and stored as an ObjectId using a Spring |
|
Converter<BigInteger, ObjectId>.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>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.</para> |
|
|
|
<para>When querying and updating <classname>MongoTemplate</classname> |
|
will use the converter to handle conversions of the |
|
<classname>Query</classname> and <classname>Update</classname> 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.</para> |
|
</section> |
|
|
|
<section> |
|
<title>Methods for saving and inserting documents</title> |
|
|
|
<para>There are several convenient methods on |
|
<classname>MongoTemplate</classname> for saving and inserting your |
|
objects. To have more fine grained control over the conversion process |
|
you can register Spring converters with the MappingMongoConverter, for |
|
example Converter<Person, DBObject> and Converter<DBObject, |
|
Person>.</para> |
|
|
|
<note> |
|
<para>The difference between insert and save operations is that a save |
|
operation will perform an insert if the object is not already |
|
present.</para> |
|
</note> |
|
|
|
<para>The simple case of using the save operation is to save a POJO. In |
|
this case the collection name will be determined by name (not fully |
|
qualfied) of the class. You may also call the save operation with a |
|
specific collection name. The collection to store the object can be |
|
overriden using mapping metadata.</para> |
|
|
|
<para>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 |
|
<classname>String</classname>, <classname>ObjectId</classname>, or |
|
<classname>BigInteger</classname>.</para> |
|
|
|
<para>Here is a basic example of using the save operation and retrieving |
|
its contents.</para> |
|
|
|
<example> |
|
<title>Inserting and retrieving documents using the |
|
MongoTemplate</title> |
|
|
|
<programlisting language="java">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(p); |
|
|
|
Person qp = mongoTemplate.findOne(query(where("age").is(33)), Person.class); |
|
</programlisting> |
|
</example> |
|
|
|
<para>The insert/save operations available to you are listed |
|
below.</para> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><literal>void</literal> <emphasis role="bold">save |
|
</emphasis> <literal>(Object objectToSave) </literal> Save the |
|
object to the default collection.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>void</literal> <emphasis role="bold">save |
|
</emphasis> <literal>(Object objectToSave, String collectionName) |
|
</literal> Save the object to the specified collection.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
|
|
<para>A similar set of insert operations is listed below</para> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><literal>void</literal> <emphasis |
|
role="bold">insert</emphasis> <literal>(Object objectToSave) |
|
</literal> Insert the object to the default collection.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>void</literal> <emphasis role="bold">insert |
|
</emphasis> <literal>(Object objectToSave, String collectionName) |
|
</literal> Insert the object to the specified collection.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
|
|
<section> |
|
<title>Which collection will my documents be saved into?</title> |
|
|
|
<para>There are two ways to manage the collection name that is used |
|
for operating on the documents. The default collection name that is |
|
used is the class name changed to start with a lower-case letter. So a |
|
<classname>com.test.Person</classname> class would be stored in the |
|
"person" collection. You can customize this by providing a different |
|
collection name using the @Document annotation. You can also override |
|
the collection name by providing your own collection name as the last |
|
parameter for the selected MongoTemplate method calls.</para> |
|
</section> |
|
|
|
<section> |
|
<title>Inserting or saving individual objects</title> |
|
|
|
<para>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</para> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><emphasis role="bold">insert</emphasis><literal> |
|
</literal> Insert an object. If there is an existing document |
|
with the same id then an error is generated.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">insertAll</emphasis> Takes a |
|
<literal>Collection </literal>of objects as the first parameter. |
|
This method ispects each object and inserts it to the |
|
appropriate collection based on the rules specified |
|
above.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">save</emphasis> Save the object |
|
ovewriting any object that might exist with the same id.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
</section> |
|
|
|
<section> |
|
<title>Inserting several objects in a batch</title> |
|
|
|
<para>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</para> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><emphasis role="bold">insert</emphasis><literal> methods |
|
that take a Collection</literal><literal> as the first |
|
argument.</literal>This inserts a list of objects in a single |
|
batch write to the database.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
</section> |
|
</section> |
|
|
|
<section id="mongodb-template-update"> |
|
<title>Updating documents in a collection</title> |
|
|
|
<para>For updates we can elect to update the first document found using |
|
<interfacename>MongoOperation</interfacename>'s method |
|
<literal>updateFirst</literal> or we can update all documents that were |
|
found to match the query using the method |
|
<literal>updateMulti</literal>. 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 <literal>$inc</literal> operator.</para> |
|
|
|
<example> |
|
<title>Updating documents using the MongoTemplate</title> |
|
|
|
<programlisting language="java">import static org.springframework.data.document.mongodb.query.Criteria.where; |
|
import static org.springframework.data.document.mongodb.query.Query; |
|
import static org.springframework.data.document.mongodb.query.Update; |
|
|
|
... |
|
|
|
WriteResult wr = mongoTemplate.updateMulti(new Query(where("accounts.accountType").is(Account.Type.SAVINGS)), |
|
new Update().inc("accounts.$.balance", 50.00), |
|
Account.class); |
|
</programlisting> |
|
</example> |
|
|
|
<para>In addition to the <classname>Query</classname> discussed above we |
|
provide the update definition using an <classname>Update</classname> |
|
object. The <classname>Update</classname> class has methods that match |
|
the update modifiers available for MongoDB.</para> |
|
|
|
<para>As you can see most methods return the |
|
<classname>Update</classname> object to provide a fluent style for the |
|
API.</para> |
|
|
|
<section> |
|
<title>Methods for executing updates for documents</title> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><emphasis role="bold">updateFirst </emphasis> Updates the |
|
first document that matches the query document criteria with the |
|
provided updated document.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">updateMulti </emphasis> Updates all |
|
objects that match the query document criteria with the provided |
|
updated document.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
|
|
<para></para> |
|
</section> |
|
|
|
<section> |
|
<title>Methods for the Update class</title> |
|
|
|
<para>The Update class can be used with a little 'syntax sugar' as its |
|
methods are meant to be chained together and you can kickstart the |
|
creation of a new Update instance via the static method |
|
<literal>public static Update update(String key, Object |
|
value)</literal> and using static imports.</para> |
|
|
|
<para>Here is a listing of methods on the Update class</para> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">addToSet |
|
</emphasis> <literal>(String key, Object value) </literal> |
|
Update using the <literal>$addToSet</literal> update |
|
modifier</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">inc |
|
</emphasis> <literal>(String key, Number inc) </literal> Update |
|
using the <literal>$inc</literal> update modifier</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">pop |
|
</emphasis> <literal>(String key, Update.Position pos) |
|
</literal> Update using the <literal>$pop</literal> update |
|
modifier</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">pull |
|
</emphasis> <literal>(String key, Object value) </literal> |
|
Update using the <literal>$pull</literal> update modifier</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">pullAll |
|
</emphasis> <literal>(String key, Object[] values) </literal> |
|
Update using the <literal>$pullAll</literal> update |
|
modifier</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">push |
|
</emphasis> <literal>(String key, Object value) </literal> |
|
Update using the <literal>$push</literal> update modifier</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">pushAll |
|
</emphasis> <literal>(String key, Object[] values) </literal> |
|
Update using the <literal>$pushAll</literal> update |
|
modifier</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">rename |
|
</emphasis> <literal>(String oldName, String newName) </literal> |
|
Update using the <literal>$rename</literal> update |
|
modifier</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">set |
|
</emphasis> <literal>(String key, Object value) </literal> |
|
Update using the <literal>$set</literal> update modifier</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Update</literal> <emphasis role="bold">unset |
|
</emphasis> <literal>(String key)</literal> Update using the |
|
<literal>$unset</literal> update modifier</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<title>Methods for removing documents</title> |
|
|
|
<para>You can use several overloaded methods to remove an object from |
|
the database.</para> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><emphasis role="bold">remove</emphasis> Remove the given |
|
document based on one of the following: a specific object |
|
instance, a query document criteria combined with a class or a |
|
query document criteria combined with a specific collection |
|
name.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
|
|
<para></para> |
|
</section> |
|
</section> |
|
|
|
<section id="mongo.query"> |
|
<title>Querying Documents</title> |
|
|
|
<para>You can express your queries using the <classname>Query</classname> |
|
and <classname>Criteria</classname> classes which have method names that |
|
mirror the native MongoDB operator names such as <literal>lt</literal>, |
|
<literal>lte</literal>, <literal>is</literal>, and others. The |
|
<classname>Query</classname> and <classname>Criteria</classname> 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.</para> |
|
|
|
<para>GeoSpatial queries are also supported and are described more in the |
|
section <link linkend="mongo.geospatial">GeoSpatial Queries</link>.</para> |
|
|
|
<section id="mongodb-template-query"> |
|
<title>Querying documents in a collection</title> |
|
|
|
<para>We saw how to retrieve a single document using the findOne and |
|
findById methods on MongoTemplate in previous sections which return a |
|
single domain object. We can also query for a collection of documents to |
|
be returned as a list of domain objects. 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.</para> |
|
|
|
<example> |
|
<title>Querying for documents using the MongoTemplate</title> |
|
|
|
<programlisting language="java">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); |
|
</programlisting> |
|
</example> |
|
|
|
<para>All find methods take a <classname>Query</classname> object as a |
|
parameter. This object defines the criteria and options used to perform |
|
the query. The criteria is specified using a |
|
<classname>Criteria</classname> object that has a static factory method |
|
named <classname>where</classname> used to instantiate a new |
|
<classname>Criteria</classname> object. We recommend using a static |
|
import for |
|
<classname>org.springframework.data.document.mongodb.query.Criteria.where</classname> |
|
and <literal>Query.query</literal> to make the query more |
|
readable.</para> |
|
|
|
<para>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.</para> |
|
|
|
<para>As you can see most methods return the |
|
<classname>Criteria</classname> object to provide a fluent style for the |
|
API.</para> |
|
|
|
<section> |
|
<title>Methods for the Criteria class</title> |
|
|
|
<para> |
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">all |
|
</emphasis> <literal>(Object o)</literal>Creates a criterion |
|
using the <literal>$all</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">and |
|
</emphasis> <literal>(String key) </literal>Adds a chained |
|
<classname>Criteria</classname> with the specified |
|
<literal>key</literal> to the current |
|
<classname>Criteria</classname> and retuns the newly created |
|
one</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis |
|
role="bold">elemMatch </emphasis> <literal>(Criteria c) |
|
</literal>Creates a criterion using the |
|
<literal>$elemMatch</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">exists |
|
</emphasis> <literal>(boolean b) </literal>Creates a criterion |
|
using the <literal>$exists</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">gt |
|
</emphasis> <literal>(Object o)</literal>Creates a criterion |
|
using the <literal>$gt</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">gte |
|
</emphasis> <literal>(Object o)</literal>Creates a criterion |
|
using the <literal>$gte</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">in |
|
</emphasis> <literal>(Object... o) </literal>Creates a criterion |
|
using the <literal>$in</literal> operator for a varargs |
|
argument.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">in |
|
</emphasis> <literal>(Collection<?> collection) |
|
</literal>Creates a criterion using the <literal>$in</literal> |
|
operator using a collection</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">is |
|
</emphasis> <literal>(Object o)</literal>Creates a criterion |
|
using the <literal>$is</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">lt |
|
</emphasis> <literal>(Object o)</literal>Creates a criterion |
|
using the <literal>$lt</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">lte |
|
</emphasis> <literal>(Object o)</literal>Creates a criterion |
|
using the <literal>$lte</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">mod |
|
</emphasis> <literal>(Number value, Number |
|
remainder)</literal>Creates a criterion using the |
|
<literal>$mod</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">ne |
|
</emphasis> <literal>(Object o)</literal>Creates a criterion |
|
using the <literal>$ne</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">nin |
|
</emphasis> <literal>(Object... o) </literal>Creates a criterion |
|
using the <literal>$nin</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">not |
|
</emphasis> <literal>()</literal>Creates a criterion using the |
|
<literal>$not</literal> meta operator which affects the clause |
|
directly following</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">or |
|
</emphasis> <literal>(List<Query> |
|
queries)</literal>Creates an or query using the |
|
<literal>$or</literal> operator for all of the provided |
|
queries</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">regex |
|
</emphasis> <literal>(String re) </literal>Creates a criterion |
|
using a <literal>$regex</literal></para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">size |
|
</emphasis> <literal>(int s)</literal>Creates a criterion using |
|
the <literal>$size</literal> operator</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">type |
|
</emphasis> <literal>(int t)</literal>Creates a criterion using |
|
the <literal>$type</literal> operator</para> |
|
</listitem> |
|
</itemizedlist> |
|
</para> |
|
</section> |
|
|
|
<para>There are also methods on the Criteria class for geospatial |
|
queries. Here is al isting but look at the section on <link |
|
linkend="mongo.geospatial">GeoSpatial Queries</link> to see them in |
|
action.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">withinCenter |
|
</emphasis> <literal>(Circle circle)</literal> Creates a geospatial |
|
criterion using <literal>$within $center</literal> operators</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis |
|
role="bold">withinCenterSphere </emphasis> <literal>(Circle circle) |
|
</literal>Creates a geospatial criterion using <literal>$within |
|
$center</literal> operators. This is only available for Mongo 1.7 |
|
and higher.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">withinBox |
|
</emphasis> <literal>(Box box)</literal> Creates a geospatial |
|
criterion using a <literal>$within $box</literal> operation |
|
<literal /></para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">near |
|
</emphasis> <literal>(Point point)</literal> Creates a geospatial |
|
criterion using a <literal>$near </literal>operation</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">nearSphere |
|
</emphasis> <literal>(Point point) </literal>Creates a geospatial |
|
criterion using <literal>$nearSphere$center</literal> operations. |
|
This is only available for Mongo 1.7 and higher.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Criteria</literal> <emphasis role="bold">maxDistance |
|
</emphasis> <literal>(double maxDistance) </literal>Creates a |
|
geospatial criterion using the <literal>$maxDistance</literal> |
|
operation, for use with $near.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>The <classname>Query</classname> class has some additional methods |
|
used to provide options for the query.</para> |
|
|
|
<section> |
|
<title>Methods for the Query class</title> |
|
|
|
<para> |
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>Query</literal> <emphasis role="bold">addCriteria |
|
</emphasis> <literal>(Criteria criteria)</literal> used to add |
|
additional criteria to the query</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>void</literal> <emphasis |
|
role="bold">or</emphasis> <literal>(List<Query> |
|
queries)</literal> Creates an or query using the |
|
<literal>$or</literal> operator for all of the provided |
|
queries</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Field</literal> <emphasis role="bold">fields |
|
</emphasis> <literal>()</literal> used to define fields to be |
|
included in the query results</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Query</literal> <emphasis role="bold">limit |
|
</emphasis> <literal>(int limit)</literal> used to limit the |
|
size of the returned results to the provided limit (used for |
|
paging)</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Query</literal> <emphasis role="bold">skip |
|
</emphasis> <literal>(int skip)</literal> used to skip the |
|
provided number of documents in the results (used for |
|
paging)</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>Sort</literal> <emphasis role="bold">sort |
|
</emphasis> <literal>()</literal> used to provide sort |
|
definition for the results</para> |
|
</listitem> |
|
</itemizedlist> |
|
</para> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<title>Methods for querying for documents</title> |
|
|
|
<para>The query methods need to specify the target type T that will be |
|
returned and they are also overloaded with an explicit collection name |
|
for queries that should operate on a collection other than the one |
|
indicated by the return type.</para> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><emphasis role="bold">findAll </emphasis> Query for a list |
|
of objects of type T from the collection.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">findOne</emphasis> Map the results of |
|
an ad-hoc query on the collection to a single instance of an |
|
object of the specified type.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">findById</emphasis> Return an object |
|
of the given id and target class.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">find</emphasis> Map the results of an |
|
ad-hoc query on the collection to a List of the specified |
|
type.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">findAndRemove</emphasis> Map the |
|
results of an ad-hoc query on the 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.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
</section> |
|
|
|
<section id="mongo.geospatial" lang=""> |
|
<title>GeoSpatial Queries</title> |
|
|
|
<para>MongoDB supports GeoSpatial queries through the use of operators |
|
such as <literal>$near</literal>, <literal>$within</literal>, and |
|
<literal>$nearSphere</literal>. Methods specific to geospatial queries |
|
are available on the <classname>Criteria</classname> class. There are |
|
also a few shape classes, <classname>Box</classname>, |
|
<classname>Circle</classname>, and <classname>Point</classname> that are |
|
used in conjunction with geospatial related Criteria methods.</para> |
|
|
|
<para>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 <classname>MappingMongoConverter</classname>.</para> |
|
|
|
<programlisting language="java">@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) + "]"; |
|
} |
|
}</programlisting> |
|
|
|
<para>To find locations within a <classname>Circle</classname>, the |
|
following query can be used.</para> |
|
|
|
<programlisting lang="" language="java">Circle circle = new Circle(-73.99171, 40.738868, 0.01); |
|
List<Venue> venues = |
|
template.find(new Query(Criteria.where("location").withinCenter(circle)), Venue.class);</programlisting> |
|
|
|
<para>To find venues within a <classname>Circle</classname> using |
|
spherical coordinates the following query can be used</para> |
|
|
|
<programlisting lang="" language="java">Circle circle = new Circle(-73.99171, 40.738868, 0.003712240453784); |
|
List<Venue> venues = |
|
template.find(new Query(Criteria.where("location").withinCenterSphere(circle)), Venue.class);</programlisting> |
|
|
|
<para>To find venues within a <classname>Box</classname> the following |
|
query can be used</para> |
|
|
|
<programlisting language="java">//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);</programlisting> |
|
|
|
<para>To find venues near a <classname>Point</classname>, the following |
|
query can be used</para> |
|
|
|
<programlisting language="java">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);</programlisting> |
|
|
|
<para>To find venues near a <classname>Point</classname> using spherical |
|
coordines the following query can be used</para> |
|
|
|
<programlisting language="java">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); |
|
</programlisting> |
|
|
|
<section> |
|
<title>Geo near queries</title> |
|
|
|
<para>MongoDB supports querying the database for geo locations and |
|
calculation the distance from a given origin at the very same time. |
|
With geo-near queries it's possible to express queries like: "find all |
|
restaurants in the surrounding 10 miles". To do so |
|
<interfacename>MongoOperations</interfacename> provides |
|
<methodname>geoNear(…)</methodname> methods taking a |
|
<classname>NearQuery</classname> as argument as well as the already |
|
familiar entity type and collection</para> |
|
|
|
<programlisting language="java">Point location = new Point(-73.99171, 40.738868); |
|
NearQuery query = NearQuery.near(location).maxDistance(new Distance(10, Metrics.MILES)); |
|
|
|
GeoResults<Restaurant> = operations.geoNear(query, Restaurant.class);</programlisting> |
|
|
|
<para>As you can see we use the <classname>NearQuery</classname> |
|
builder API to set up a query to return all |
|
<classname>Restaurant</classname> instances surrounding the given |
|
<classname>Point</classname> by 10 miles maximum. The |
|
<classname>Metrics</classname> enum used here actually implements an |
|
interface so that other metrics could be plugged into a distance as |
|
well. A <interfacename>Metric</interfacename> is backed by a |
|
multiplier to transform the distance value of the given metric into |
|
native distances. The sample shown here would consider the 10 to be |
|
miles. Using one of the pre-built in metrics (miles and kilometers) |
|
will automatically trigger the spherical flag to be set on the query. |
|
If you want to avoid that, simply hand in plain |
|
<classname>double</classname> values into |
|
<methodname>maxDistance(…)</methodname>. For more information see the |
|
JavaDoc of <classname>NearQuery</classname> and |
|
<classname>Distance</classname>.</para> |
|
|
|
<para>The geo near operations return a |
|
<classname>GeoResults</classname> wrapper object that encapsulates |
|
<classname>GeoResult</classname> instances. The wrapping |
|
<classname>GeoResults</classname> allows to access the average |
|
distance of all results. A single <classname>GeoResult</classname> |
|
object simply carries the entity found plus its distance from the |
|
origin.</para> |
|
</section> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<title>Overriding default mapping with custom converters</title> |
|
|
|
<para>In order to have more fine grained control over the mapping process |
|
you can register Spring converters with the |
|
<classname>MongoConverter</classname> implementations such as the |
|
<classname>MappingMongoConverter</classname>.</para> |
|
|
|
<para>The <classname>MappingMongoConverter</classname> checks to see if |
|
there are any Spring converters that can handle a specific class before |
|
attempting to map the object itself. To 'hijack' the normal mapping |
|
strategies of the <classname>MappingMongoConverter</classname>, perhaps |
|
for increased performance or other custom mapping needs, you first need to |
|
create an implementation of the Spring |
|
<interfacename>Converter</interfacename> interface and then register it |
|
with the MappingConverter.</para> |
|
|
|
<note> |
|
<para>For more information on the Spring type conversion service see the |
|
reference docs <ulink |
|
url="http://static.springsource.org/spring/docs/3.0.x/reference/validation.html#core-convert">here</ulink>.</para> |
|
</note> |
|
|
|
<section> |
|
<title>Saving using a registered Spring Converter</title> |
|
|
|
<para>An example implementation of the |
|
<interfacename>Converter</interfacename> that converts from a Person |
|
object to a <classname>com.mongodb.DBObject</classname> is shown |
|
below</para> |
|
|
|
<programlisting language="java">import org.springframework.core.convert.converter.Converter; |
|
|
|
import com.mongodb.BasicDBObject; |
|
import com.mongodb.DBObject; |
|
|
|
public class PersonWriteConverter implements Converter<Person, DBObject> { |
|
|
|
public DBObject convert(Person source) { |
|
DBObject dbo = new BasicDBObject(); |
|
dbo.put("_id", source.getId()); |
|
dbo.put("name", source.getFirstName()); |
|
dbo.put("age", source.getAge()); |
|
return dbo; |
|
} |
|
|
|
}</programlisting> |
|
</section> |
|
|
|
<section> |
|
<title>Reading using a Spring Converter</title> |
|
|
|
<para>An example implemention of a Converter that converts from a |
|
DBObject ot a Person object is shownn below</para> |
|
|
|
<programlisting language="java">public class PersonReadConverter implements Converter<DBObject, Person> { |
|
|
|
public Person convert(DBObject source) { |
|
Person p = new Person((ObjectId) source.get("_id"), (String) source.get("name")); |
|
p.setAge((Integer) source.get("age")); |
|
return p; |
|
} |
|
|
|
}</programlisting> |
|
</section> |
|
|
|
<section> |
|
<title>Registering Spring Converters with the MongoConverter</title> |
|
|
|
<para>The mongo XSD namespace provides a convenience way to register |
|
Spring Converters as shown below as well as configuring it into a |
|
MongoTemplate.</para> |
|
|
|
<programlisting language="java"><mongo:db-factory dbname="database"/> |
|
|
|
<mongo:mapping-converter> |
|
<mongo:custom-converters> |
|
<mongo:converter ref="readConverter"/> |
|
<mongo:converter> |
|
<bean class="org.springframework.data.document.mongodb.PersonWriteConverter"/> |
|
</mongo:converter> |
|
</mongo:custom-converters> |
|
</mongo:mapping-converter> |
|
|
|
<bean id="readConverter" class="org.springframework.data.document.mongodb.PersonReadConverter"/> |
|
|
|
<bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate"> |
|
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> |
|
<constructor-arg name="mongoConverter" ref="mappingConverter"/> |
|
</bean> |
|
</programlisting> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<title>Index and Collection managment</title> |
|
|
|
<para>MongoTemplate provides a few methods for managing indexes and |
|
collections.</para> |
|
|
|
<section> |
|
<title>Methods for creating an Index</title> |
|
|
|
<para>We can create an index on a collection to improve query |
|
performance.</para> |
|
|
|
<example> |
|
<title>Creating an index using the MongoTemplate</title> |
|
|
|
<programlisting language="java">mongoTemplate.ensureIndex(new Index().on("name",Order.ASCENDING), Person.class); </programlisting> |
|
</example> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><emphasis role="bold">ensureIndex </emphasis>Ensure that an |
|
index for the provided IndexDefinition exists for the |
|
collection.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
|
|
<para>You can create both standard indexes and geospatial indexes using |
|
the classes <classname>IndexDefinition</classname> and |
|
<classname>GeoSpatialIndex</classname> respectfully. For example, given |
|
the Venue class defined in a previous section, you would declare a |
|
geospatial query as shown below</para> |
|
|
|
<programlisting language="java">mongoTemplate.ensureIndex(new GeospatialIndex("location"), Venue.class);</programlisting> |
|
</section> |
|
|
|
<section> |
|
<title>Methods for working with a Collection</title> |
|
|
|
<para>It's time to look at some code examples showing how to use the |
|
<classname>MongoTemplate</classname>. First we look at creating our |
|
first collection.</para> |
|
|
|
<example> |
|
<title>Working with collections using the MongoTemplate</title> |
|
|
|
<programlisting language="java">DBCollection collection = null; |
|
if (!mongoTemplate.getCollectionNames().contains("MyNewCollection")) { |
|
collection = mongoTemplate.createCollection("MyNewCollection"); |
|
} |
|
|
|
mongoTemplate.dropCollection("MyNewCollection"); </programlisting> |
|
</example> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><emphasis role="bold">getCollectionNames</emphasis> Returns |
|
a set of collection names.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">collectionExists</emphasis> Check to |
|
see if a collection with a given name exists.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">createCollection</emphasis> Create an |
|
uncapped collection</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">dropCollection</emphasis> Drop the |
|
collection</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis role="bold">getCollection</emphasis> Get a |
|
collection by name, creating it if it doesn't exist.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<title>Executing Commands</title> |
|
|
|
<para>You can also get at the Mongo driver's <classname>DB.command( |
|
)</classname> method using the executeCommand methods on MongoTemplate. |
|
These will also perform exception translation into Spring's Data Access |
|
Exception hierarchy.</para> |
|
|
|
<section> |
|
<title>Methods for executing commands</title> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><literal>CommandResult</literal> <emphasis |
|
role="bold">executeCommand </emphasis> <literal>(DBObject command) |
|
</literal> Execute a MongoDB command.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>CommandResult</literal> <emphasis |
|
role="bold">executeCommand </emphasis> <literal>(String |
|
jsonCommand) </literal> Execute the a MongoDB command expressed as |
|
a JSON string.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
</section> |
|
</section> |
|
|
|
<section id="mongodb.mapping-usage.events"> |
|
<title>Lifecycle Events</title> |
|
|
|
<para>Built into the MongoDB mapping framework are several |
|
<classname>org.springframework.context.ApplicationEvent</classname> events |
|
that your application can respond to by registering special beans in the |
|
<code>ApplicationContext</code>. 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.</para> |
|
|
|
<para>To intercept an object before it goes through the conversion process |
|
(which turns your domain object into a |
|
<classname>com.mongodb.DBObject</classname>), you'd register a subclass of |
|
<classname>AbstractMongoEventListener</classname> that overrides the |
|
<code>onBeforeConvert</code> method. When the event is dispatched, your |
|
listener will be called and passed the domain object before it goes into |
|
the converter.</para> |
|
|
|
<example> |
|
<programlisting language="java">public class BeforeConvertListener extends AbstractMongoEventListener<Person> { |
|
@Override |
|
public void onBeforeConvert(Person p) { |
|
... does some auditing manipulation, set timestamps, whatever ... |
|
} |
|
} </programlisting> |
|
</example> |
|
|
|
<para>To intercept an object before it goes into the database, you'd |
|
register a subclass of |
|
<classname>org.springframework.data.document.mongodb.mapping.event.AbstractMappingEventListener</classname> |
|
that overrides the <code>onBeforeSave</code> method. When the event is |
|
dispatched, your listener will be called and passed the domain object and |
|
the converted <classname>com.mongodb.DBObject</classname>.</para> |
|
|
|
<example> |
|
<programlisting language="java">public class BeforeSaveListener extends AbstractMongoEventListener<Person> { |
|
@Override |
|
public void onBeforeSave(Person p, DBObject dbo) { |
|
… change values, delete them, whatever … |
|
} |
|
} </programlisting> |
|
</example> |
|
|
|
<para>Simply declaring these beans in your Spring ApplicationContext will |
|
cause them to be invoked whenever the event is dispatched.</para> |
|
|
|
<para>The list of callback methods that are present in |
|
AbstractMappingEventListener are</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><methodname>onBeforeConvert</methodname> - called in |
|
MongoTemplate insert, insertList and save operations before the object |
|
is converted to a DBObject using a MongoConveter.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><methodname>onBeforeSave</methodname> - called in MongoTemplate |
|
insert, insertList and save operations <emphasis>before</emphasis> |
|
inserting/saving the DBObject in the database.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><methodname>onAfterSave</methodname> - called in MongoTemplate |
|
insert, insertList and save operations <emphasis>after</emphasis> |
|
inserting/saving the DBObject in the database.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><methodname>onAfterLoad</methodname> - called in MongoTempnlate |
|
find, findAndRemove, findOne and getCollection methods after the |
|
DBObject is retrieved from the database.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><methodname>onAfterConvert</methodname> - called in |
|
MongoTempnlate find, findAndRemove, findOne and getCollection methods |
|
after the DBObject retrieved from the database was converted to a |
|
POJO.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</section> |
|
|
|
<section id="mongo.exception" label=""> |
|
<title>Exception Translation</title> |
|
|
|
<para>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 |
|
<classname>org.springframework.dao.support.PersistenceExceptionTranslator</classname> |
|
interface.</para> |
|
|
|
<para>The motivation behind mapping to Spring's <ulink |
|
url="http://static.springsource.org/spring/docs/3.0.x/reference/dao.html#dao-exceptions">consistent |
|
data access exception hierarchy</ulink> is that you are then able to write |
|
portable and descriptive exception handling code without resorting to |
|
coding against <ulink |
|
url="http://www.mongodb.org/display/DOCS/Error+Codes">MongoDB error |
|
codes</ulink>. All of Spring's data access exceptions are inherited from |
|
the root <classname>DataAccessException</classname> 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.</para> |
|
|
|
<para>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.</para> |
|
</section> |
|
|
|
<section id="mongo.executioncallback"> |
|
<title>Execution Callback</title> |
|
|
|
<para>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 |
|
<classname>MongoTemplate</classname>.</para> |
|
|
|
<para>Here is a list of execute callback methods.</para> |
|
|
|
<para><itemizedlist> |
|
<listitem> |
|
<para><literal><T> T</literal> <emphasis role="bold">execute |
|
</emphasis> <literal>(Class<?> entityClass, |
|
CollectionCallback<T> action) </literal> Executes the given |
|
CollectionCallback for the entity collection of the specified |
|
class.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal><T> T</literal> <emphasis role="bold">execute |
|
</emphasis> <literal>(String collectionName, |
|
CollectionCallback<T> action) </literal> Executes the given |
|
CollectionCallback on the collection of the given name.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal><T> T</literal> <emphasis role="bold">execute |
|
</emphasis> <literal>(DbCallback<T> action) </literal> |
|
Executes a DbCallback translating any exceptions as |
|
necessary.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal><T> T</literal> <emphasis role="bold">execute |
|
</emphasis> <literal>(String collectionName, DbCallback<T> |
|
action) </literal> Executes a DbCallback on the collection of the |
|
given name translating any exceptions as necessary.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal><T> T</literal> <emphasis |
|
role="bold">executeInSession </emphasis> |
|
<literal>(DbCallback<T> action) </literal> 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.</para> |
|
</listitem> |
|
</itemizedlist></para> |
|
|
|
<para>Here is an example that uses the CollectionCallback to return |
|
information about an index.</para> |
|
|
|
<programlisting language="java"> boolean hasIndex = template.execute("geolocation", new CollectionCallback<Boolean>() { |
|
public Boolean doInCollection(Venue.class, 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; |
|
} |
|
});</programlisting> |
|
</section> |
|
</chapter> |