26 changed files with 3411 additions and 5695 deletions
@ -1,99 +0,0 @@
@@ -1,99 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> |
||||
<book xmlns:xi="http://www.w3.org/2001/XInclude"> |
||||
<bookinfo> |
||||
<title>Spring Data MongoDB - Reference Documentation</title> |
||||
|
||||
<releaseinfo>&version;</releaseinfo> |
||||
|
||||
<authorgroup> |
||||
<author> |
||||
<firstname>Mark</firstname> |
||||
<surname>Pollack</surname> |
||||
</author> |
||||
|
||||
<author> |
||||
<firstname>Thomas</firstname> |
||||
<surname>Risberg</surname> |
||||
</author> |
||||
|
||||
<author> |
||||
<firstname>Oliver</firstname> |
||||
<surname>Gierke</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Costin</firstname> |
||||
<surname>Leau</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Jon</firstname> |
||||
<surname>Brisbin</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Thomas</firstname> |
||||
<surname>Darimont</surname> |
||||
</author> |
||||
<author> |
||||
<firstname>Christoph</firstname> |
||||
<surname>Strobl</surname> |
||||
</author> |
||||
</authorgroup> |
||||
|
||||
<legalnotice> |
||||
<para>Copies of this document may be made for your own use and for |
||||
distribution to others, provided that you do not charge any fee for such |
||||
copies and further provided that each copy contains this Copyright |
||||
Notice, whether distributed in print or electronically.</para> |
||||
</legalnotice> |
||||
|
||||
<pubdate /> |
||||
|
||||
<copyright> |
||||
<year>2008-2014</year> |
||||
|
||||
<holder> The original authors.</holder> |
||||
</copyright> |
||||
|
||||
<productname>Spring Data MongoDB - Reference Documentation</productname> |
||||
</bookinfo> |
||||
|
||||
<toc/> |
||||
|
||||
<xi:include href="preface.xml"/> |
||||
|
||||
<part id="introduction"> |
||||
<title>Introduction</title> |
||||
|
||||
<xi:include href="introduction/introduction.xml"/> |
||||
<xi:include href="introduction/requirements.xml"/> |
||||
<xi:include href="introduction/getting-started.xml"/> |
||||
<xi:include href="https://raw.github.com/spring-projects/spring-data-commons/1.9.0.M1/src/docbkx/repositories.xml"> |
||||
<xi:fallback href="../../../spring-data-commons/src/docbkx/repositories.xml" /> |
||||
</xi:include> |
||||
</part> |
||||
|
||||
<part id="reference"> |
||||
<title>Reference Documentation</title> |
||||
|
||||
<xi:include href="reference/introduction.xml"/> |
||||
<xi:include href="reference/mongodb.xml"/> |
||||
<xi:include href="reference/mongo-repositories.xml"/> |
||||
<xi:include href="reference/mapping.xml"/> |
||||
<xi:include href="reference/cross-store.xml"/> |
||||
<xi:include href="reference/logging.xml"/> |
||||
<xi:include href="reference/jmx.xml"/> |
||||
</part> |
||||
|
||||
<part id="appendix"> |
||||
<title>Appendix</title> |
||||
|
||||
<xi:include href="https://raw.github.com/spring-projects/spring-data-commons/1.9.0.M1/src/docbkx/repository-namespace-reference.xml"> |
||||
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-namespace-reference.xml" /> |
||||
</xi:include> |
||||
<xi:include href="https://raw.github.com/spring-projects/spring-data-commons/1.9.0.M1/src/docbkx/repository-query-keywords-reference.xml"> |
||||
<xi:fallback href="../../../spring-data-commons/src/docbkx/repository-query-keywords-reference.xml" /> |
||||
</xi:include> |
||||
</part> |
||||
|
||||
</book> |
||||
@ -1,63 +0,0 @@
@@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> |
||||
<chapter id="get-started"> |
||||
<title>Additional Help Resources</title> |
||||
|
||||
<para>Learning a new framework is not always straight forward. In this |
||||
section, we try to provide what we think is an easy to follow guide for |
||||
starting with Spring Data Document module. However, if you encounter issues |
||||
or you are just looking for an advice, feel free to use one of the links |
||||
below:</para> |
||||
|
||||
<section id="get-started:help"> |
||||
<title>Support</title> |
||||
|
||||
<para>There are a few support options available:</para> |
||||
|
||||
<section id="get-started:help:community"> |
||||
<title>Community Forum</title> |
||||
|
||||
<para>Spring Data on Stackoverflow <ulink |
||||
url="http://stackoverflow.com/questions/tagged/spring-data">Stackoverflow |
||||
</ulink> is a tag for all Spring Data (not just Document) users to share |
||||
information and help each other. Note that registration is needed |
||||
<emphasis>only</emphasis> for posting.</para> |
||||
</section> |
||||
|
||||
<section id="get-started:help:professional"> |
||||
<title>Professional Support</title> |
||||
|
||||
<para>Professional, from-the-source support, with guaranteed response |
||||
time, is available from <ulink url="http://gopivotal.com/">Pivotal |
||||
Sofware, Inc.</ulink>, the company behind Spring Data and Spring.</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="get-started:up-to-date"> |
||||
<title>Following Development</title> |
||||
|
||||
<para>For information on the Spring Data Mongo source code repository, |
||||
nightly builds and snapshot artifacts please see the <ulink |
||||
url="http://projects.spring.io/spring-data-mongodb/">Spring Data Mongo |
||||
homepage</ulink>.</para> |
||||
|
||||
<para>You can help make Spring Data best serve the needs of the Spring |
||||
community by interacting with developers through the Community on <ulink |
||||
url="http://stackoverflow.com/questions/tagged/spring-data">Stackoverflow</ulink>. |
||||
To follow developer activity look for the mailing list information on the |
||||
Spring Data Mongo homepage.</para> |
||||
|
||||
<para>If you encounter a bug or want to suggest an improvement, please |
||||
create a ticket on the Spring Data issue <ulink |
||||
url="https://jira.spring.io/browse/DATAMONGO">tracker</ulink>.</para> |
||||
|
||||
<para>To stay up to date with the latest news and announcements in the |
||||
Spring eco system, subscribe to the Spring Community <ulink |
||||
url="https://spring.io">Portal</ulink>.</para> |
||||
|
||||
<para>Lastly, you can follow the SpringSource Data <ulink |
||||
url="https://spring.io/blog">blog </ulink>or the project team on Twitter |
||||
(<ulink url="http://twitter.com/SpringData">SpringData</ulink>).</para> |
||||
</section> |
||||
</chapter> |
||||
@ -1,95 +0,0 @@
@@ -1,95 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> |
||||
<partintro> |
||||
<para><para>This document is the reference guide for Spring Data - Document |
||||
Support. It explains Document module concepts and semantics and the syntax |
||||
for various stores namespaces. </para><para>This section provides some basic |
||||
introduction to Spring and Document database. The rest of the document |
||||
refers only to Spring Data Document features and assumes the user is |
||||
familiar with document databases such as MongoDB and CouchDB as well as |
||||
Spring concepts. </para><section id="get-started:first-steps:spring"> |
||||
<title>Knowing Spring</title> |
||||
|
||||
<para>Spring Data uses Spring framework's <ulink |
||||
url="http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/spring-core.html">core</ulink> |
||||
functionality, such as the <ulink |
||||
url="http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html">IoC</ulink> |
||||
container, <ulink |
||||
url="http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html#core-convert">type |
||||
conversion system</ulink>, <ulink |
||||
url="http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/expressions.html">expression |
||||
language</ulink>, <ulink |
||||
url="http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/jmx.html">JMX |
||||
integration</ulink>, and portable <ulink |
||||
url="http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/dao.html#dao-exceptions">DAO |
||||
exception hierarchy</ulink>. While it is not important to know the |
||||
Spring APIs, understanding the concepts behind them is. At a minimum, |
||||
the idea behind IoC should be familiar for whatever IoC container you |
||||
choose to use.</para> |
||||
|
||||
<para>The core functionality of the MongoDB and CouchDB support can be |
||||
used directly, with no need to invoke the IoC services of the Spring |
||||
Container. This is much like <classname>JdbcTemplate</classname> which |
||||
can be used 'standalone' without any other services of the Spring |
||||
container. To leverage all the features of Spring Data document, such as |
||||
the repository support, you will need to configure some parts of the |
||||
library using Spring.</para> |
||||
|
||||
<para>To learn more about Spring, you can refer to the comprehensive |
||||
(and sometimes disarming) documentation that explains in detail the |
||||
Spring Framework. There are a lot of articles, blog entries and books on |
||||
the matter - take a look at the Spring framework <ulink |
||||
url="https://spring.io/docs">home page </ulink> for |
||||
more information.</para> |
||||
</section><section id="get-started:first-steps:nosql"> |
||||
<title>Knowing NoSQL and Document databases</title> |
||||
|
||||
<para>NoSQL stores have taken the storage world by storm. It is a vast |
||||
domain with a plethora of solutions, terms and patterns (to make things |
||||
worth even the term itself has multiple <ulink |
||||
url="http://www.google.com/search?q=nosoql+acronym">meanings</ulink>). |
||||
While some of the principles are common, it is crucial that the user is |
||||
familiar to some degree with the stores supported by DATADOC. The best |
||||
way to get acquainted to this solutions is to read their documentation |
||||
and follow their examples - it usually doesn't take more then 5-10 |
||||
minutes to go through them and if you are coming from an RDMBS-only |
||||
background many times these exercises can be an eye opener.</para> |
||||
|
||||
<para>The jumping off ground for learning about MongoDB is <ulink |
||||
url="http://www.mongodb.org/">www.mongodb.org</ulink>. Here is a list of |
||||
other useful resources.</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>The <ulink url="http://docs.mongodb.org/manual/">manual</ulink> introduces MongoDB and contains links to |
||||
getting started guides, reference documentation and tutorials.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>The <ulink url="http://try.mongodb.org/">online shell</ulink> |
||||
provides a convenient way to interact with a MongoDB instance in |
||||
combination with the online <ulink type="" |
||||
url="http://docs.mongodb.org/manual/tutorial/getting-started/">tutorial.</ulink></para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>MongoDB <ulink |
||||
url="http://docs.mongodb.org/ecosystem/drivers/java/">Java |
||||
Language Center</ulink></para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>Several <ulink |
||||
url="http://www.mongodb.org/books">books</ulink> |
||||
available for purchase</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>Karl Seguin's online book: "<ulink |
||||
url="http://openmymind.net/mongodb.pdf">The Little MongoDB |
||||
Book</ulink>"</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
</section></para> |
||||
</partintro> |
||||
@ -1,14 +0,0 @@
@@ -1,14 +0,0 @@
|
||||
<chapter id="requirements"> |
||||
<title>Requirements</title> |
||||
|
||||
<para>Spring Data MongoDB 1.x binaries requires JDK level 6.0 and above, |
||||
and |
||||
<ulink url="https://spring.io/docs">Spring Framework</ulink> |
||||
3.2.x and above. |
||||
</para> |
||||
<para> |
||||
In terms of document stores, |
||||
<ulink url="http://www.mongodb.org/">MongoDB</ulink> |
||||
preferably version 2.4. |
||||
</para> |
||||
</chapter> |
||||
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> |
||||
<preface id="preface"> |
||||
<title>Preface</title> |
||||
|
||||
<para>The Spring Data MongoDB project applies core Spring concepts to |
||||
the development of solutions using the MongoDB document style data store. |
||||
We provide a "template" as a high-level abstraction for storing and querying |
||||
documents. You will notice similarities to the JDBC support in the Spring |
||||
Framework. |
||||
</para> |
||||
</preface> |
||||
@ -1,293 +0,0 @@
@@ -1,293 +0,0 @@
|
||||
<?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.cross.store"> |
||||
<title>Cross Store support</title> |
||||
|
||||
<para>Sometimes you need to store data in multiple data stores and these |
||||
data stores can be of different types. One might be relational while the |
||||
other a document store. For this use case we have created a separate module |
||||
in the MongoDB support that handles what we call cross-store support. The |
||||
current implementation is based on JPA as the driver for the relational |
||||
database and we allow select fields in the Entities to be stored in a Mongo |
||||
database. In addition to allowing you to store your data in two stores we |
||||
also coordinate persistence operations for the non-transactional MongoDB |
||||
store with the transaction life-cycle for the relational database.</para> |
||||
|
||||
<section id="mongodb_cross-store-configuration"> |
||||
<title>Cross Store Configuration</title> |
||||
|
||||
<para>Assuming that you have a working JPA application and would like to |
||||
add some cross-store persistence for MongoDB. What do you have to add to |
||||
your configuration?</para> |
||||
|
||||
<para>First of all you need to add a dependency on the |
||||
<filename>spring-data-mongodb-cross-store</filename> module. Using Maven |
||||
this is done by adding a dependency to your pom:</para> |
||||
|
||||
<example> |
||||
<title>Example Maven pom.xml with spring-data-mongodb-cross-store |
||||
dependency</title> |
||||
|
||||
<programlisting language="xml"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
... |
||||
|
||||
<!-- Spring Data --> |
||||
<dependency> |
||||
<groupId>org.springframework.data</groupId> |
||||
<artifactId>spring-data-mongodb-cross-store</artifactId> |
||||
<version>${spring.data.mongo.version}</version> |
||||
</dependency> |
||||
|
||||
|
||||
... |
||||
|
||||
</project> |
||||
</programlisting> |
||||
</example> |
||||
|
||||
<para>Once this is done we need to enable AspectJ for the project. The |
||||
cross-store support is implemented using AspectJ aspects so by enabling |
||||
compile time AspectJ support the cross-store features will become |
||||
available to your project. In Maven you would add an additional plugin to |
||||
the <build> section of the pom:</para> |
||||
|
||||
<example> |
||||
<title>Example Maven pom.xml with AspectJ plugin enabled</title> |
||||
|
||||
<programlisting language="xml"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
... |
||||
|
||||
<build> |
||||
<plugins> |
||||
|
||||
... |
||||
|
||||
<plugin> |
||||
<groupId>org.codehaus.mojo</groupId> |
||||
<artifactId>aspectj-maven-plugin</artifactId> |
||||
<version>1.0</version> |
||||
<dependencies> |
||||
<!-- NB: You must use Maven 2.0.9 or above or these are ignored (see MNG-2972) --> |
||||
<dependency> |
||||
<groupId>org.aspectj</groupId> |
||||
<artifactId>aspectjrt</artifactId> |
||||
<version>${aspectj.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.aspectj</groupId> |
||||
<artifactId>aspectjtools</artifactId> |
||||
<version>${aspectj.version}</version> |
||||
</dependency> |
||||
</dependencies> |
||||
<executions> |
||||
<execution> |
||||
<goals> |
||||
<goal>compile</goal> |
||||
<goal>test-compile</goal> |
||||
</goals> |
||||
</execution> |
||||
</executions> |
||||
<configuration> |
||||
<outxml>true</outxml> |
||||
<aspectLibraries> |
||||
<aspectLibrary> |
||||
<groupId>org.springframework</groupId> |
||||
<artifactId>spring-aspects</artifactId> |
||||
</aspectLibrary> |
||||
<aspectLibrary> |
||||
<groupId>org.springframework.data</groupId> |
||||
<artifactId>spring-data-mongodb-cross-store</artifactId> |
||||
</aspectLibrary> |
||||
</aspectLibraries> |
||||
<source>1.6</source> |
||||
<target>1.6</target> |
||||
</configuration> |
||||
</plugin> |
||||
|
||||
... |
||||
|
||||
</plugins> |
||||
</build> |
||||
|
||||
... |
||||
|
||||
</project> |
||||
</programlisting> |
||||
</example> |
||||
|
||||
<para>Finally, you need to configure your project to use MongoDB and also |
||||
configure the aspects that are used. The following XML snippet should be |
||||
added to your application context:</para> |
||||
|
||||
<example> |
||||
<title>Example application context with MongoDB and cross-store aspect |
||||
support</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:jdbc="http://www.springframework.org/schema/jdbc" |
||||
xmlns:jpa="http://www.springframework.org/schema/data/jpa" |
||||
xmlns:mongo="http://www.springframework.org/schema/data/mongo" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo |
||||
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd |
||||
http://www.springframework.org/schema/jdbc |
||||
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd |
||||
http://www.springframework.org/schema/beans |
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd |
||||
http://www.springframework.org/schema/data/jpa |
||||
http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd"> |
||||
|
||||
... |
||||
|
||||
<!-- Mongo config --> |
||||
<mongo:mongo host="localhost" port="27017"/> |
||||
|
||||
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> |
||||
<constructor-arg name="mongo" ref="mongo"/> |
||||
<constructor-arg name="databaseName" value="test"/> |
||||
<constructor-arg name="defaultCollectionName" value="cross-store"/> |
||||
</bean> |
||||
|
||||
<bean class="org.springframework.data.mongodb.core.MongoExceptionTranslator"/> |
||||
|
||||
<!-- Mongo cross-store aspect config --> |
||||
<bean class="org.springframework.data.persistence.document.mongo.MongoDocumentBacking" |
||||
factory-method="aspectOf"> |
||||
<property name="changeSetPersister" ref="mongoChangeSetPersister"/> |
||||
</bean> |
||||
<bean id="mongoChangeSetPersister" |
||||
class="org.springframework.data.persistence.document.mongo.MongoChangeSetPersister"> |
||||
<property name="mongoTemplate" ref="mongoTemplate"/> |
||||
<property name="entityManagerFactory" ref="entityManagerFactory"/> |
||||
</bean> |
||||
|
||||
... |
||||
|
||||
</beans> |
||||
</programlisting> |
||||
</example> |
||||
|
||||
<para></para> |
||||
|
||||
<para></para> |
||||
</section> |
||||
|
||||
<section id="mongodb_cross-store-application"> |
||||
<title>Writing the Cross Store Application</title> |
||||
|
||||
<para>We are assuming that you have a working JPA application so we will |
||||
only cover the additional steps needed to persist part of your Entity in |
||||
your Mongo database. First you need to identify the field you want |
||||
persisted. It should be a domain class and follow the general rules for the |
||||
Mongo mapping support covered in previous chapters. The field you want |
||||
persisted in MongoDB should be annotated using the |
||||
<classname>@RelatedDocument</classname> annotation. That is really all you |
||||
need to do!. The cross-store aspects take care of the rest. This includes |
||||
marking the field with @Transient so it won't be persisted using JPA, |
||||
keeping track of any changes made to the field value and writing them to |
||||
the database on successful transaction completion, loading the document |
||||
from MongoDB the first time the value is used in your application. Here is |
||||
an example of a simple Entity that has a field annotated with |
||||
@RelatedEntity.</para> |
||||
|
||||
<example> |
||||
<title>Example of Entity with @RelatedDocument</title> |
||||
|
||||
<programlisting language="java">@Entity |
||||
public class Customer { |
||||
|
||||
@Id |
||||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
||||
private Long id; |
||||
|
||||
private String firstName; |
||||
|
||||
private String lastName; |
||||
|
||||
@RelatedDocument |
||||
private SurveyInfo surveyInfo; |
||||
|
||||
// getters and setters omitted |
||||
|
||||
} </programlisting> |
||||
</example> |
||||
|
||||
<example> |
||||
<title>Example of domain class to be stored as document</title> |
||||
|
||||
<programlisting language="java">public class SurveyInfo { |
||||
|
||||
private Map<String, String> questionsAndAnswers; |
||||
|
||||
public SurveyInfo() { |
||||
this.questionsAndAnswers = new HashMap<String, String>(); |
||||
} |
||||
|
||||
public SurveyInfo(Map<String, String> questionsAndAnswers) { |
||||
this.questionsAndAnswers = questionsAndAnswers; |
||||
} |
||||
|
||||
public Map<String, String> getQuestionsAndAnswers() { |
||||
return questionsAndAnswers; |
||||
} |
||||
|
||||
public void setQuestionsAndAnswers(Map<String, String> questionsAndAnswers) { |
||||
this.questionsAndAnswers = questionsAndAnswers; |
||||
} |
||||
|
||||
public SurveyInfo addQuestionAndAnswer(String question, String answer) { |
||||
this.questionsAndAnswers.put(question, answer); |
||||
return this; |
||||
} |
||||
} </programlisting> |
||||
</example> |
||||
|
||||
<para>Once the SurveyInfo has been set on the Customer object above the |
||||
MongoTemplate that was configured above is used to save the SurveyInfo |
||||
along with some metadata about the JPA Entity is stored in a MongoDB |
||||
collection named after the fully qualified name of the JPA Entity class. |
||||
The following code:</para> |
||||
|
||||
<example> |
||||
<title>Example of code using the JPA Entity configured for cross-store |
||||
persistence</title> |
||||
|
||||
<programlisting language="java"> Customer customer = new Customer(); |
||||
customer.setFirstName("Sven"); |
||||
customer.setLastName("Olafsen"); |
||||
SurveyInfo surveyInfo = new SurveyInfo() |
||||
.addQuestionAndAnswer("age", "22") |
||||
.addQuestionAndAnswer("married", "Yes") |
||||
.addQuestionAndAnswer("citizenship", "Norwegian"); |
||||
customer.setSurveyInfo(surveyInfo); |
||||
customerRepository.save(customer); |
||||
</programlisting> |
||||
</example> |
||||
|
||||
<para>Executing the code above results in the following JSON document |
||||
stored in MongoDB.</para> |
||||
|
||||
<example> |
||||
<title>Example of JSON document stored in MongoDB</title> |
||||
|
||||
<programlisting language="java">{ "_id" : ObjectId( "4d9e8b6e3c55287f87d4b79e" ), |
||||
"_entity_id" : 1, |
||||
"_entity_class" : "org.springframework.data.mongodb.examples.custsvc.domain.Customer", |
||||
"_entity_field_name" : "surveyInfo", |
||||
"questionsAndAnswers" : { "married" : "Yes", |
||||
"age" : "22", |
||||
"citizenship" : "Norwegian" }, |
||||
"_entity_field_class" : "org.springframework.data.mongodb.examples.custsvc.domain.SurveyInfo" }</programlisting> |
||||
</example> |
||||
|
||||
<para></para> |
||||
</section> |
||||
</chapter> |
||||
@ -1,21 +0,0 @@
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> |
||||
<partintro> |
||||
<title>Document Structure</title> |
||||
|
||||
<para>This part of the reference documentation explains the core functionality |
||||
offered by Spring Data Document. |
||||
</para> |
||||
|
||||
<para> |
||||
<xref linkend="mongo.core"/> |
||||
introduces the MongoDB module feature set. |
||||
</para> |
||||
|
||||
<para> |
||||
<xref linkend="mongo.repositories"/> |
||||
introduces the repository support for MongoDB. |
||||
</para> |
||||
|
||||
</partintro> |
||||
@ -1,109 +0,0 @@
@@ -1,109 +0,0 @@
|
||||
<?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.jmx"> |
||||
<title>JMX support</title> |
||||
|
||||
<para>The JMX support for MongoDB exposes the results of executing the |
||||
'serverStatus' command on the admin database for a single MongoDB server |
||||
instance. It also exposes an administrative MBean, MongoAdmin which will let |
||||
you perform administrative operations such as drop or create a database. The |
||||
JMX features build upon the JMX feature set available in the Spring |
||||
Framework. See <ulink |
||||
url="http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/jmx.html">here |
||||
</ulink> for more details.</para> |
||||
|
||||
<section id="mongodb:jmx-configuration"> |
||||
<title>MongoDB JMX Configuration</title> |
||||
|
||||
<para>Spring's Mongo namespace enables you to easily enable JMX |
||||
functionality</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 |
||||
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"> |
||||
|
||||
<beans> |
||||
|
||||
<!-- Default bean name is 'mongo' --> |
||||
<mongo:mongo host="localhost" port="27017"/> |
||||
|
||||
<!-- by default look for a Mongo object named 'mongo' --> |
||||
<mongo:jmx/> |
||||
|
||||
<context:mbean-export/> |
||||
|
||||
<!-- To translate any MongoExceptions thrown in @Repository annotated classes --> |
||||
<context:annotation-config/> |
||||
|
||||
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean" p:port="1099" /> |
||||
|
||||
<!-- Expose JMX over RMI --> |
||||
<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" |
||||
depends-on="registry" |
||||
p:objectName="connector:name=rmi" |
||||
p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector" /> |
||||
|
||||
</beans> </programlisting> |
||||
</example> |
||||
|
||||
<para>This will expose several MBeans</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>AssertMetrics</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>BackgroundFlushingMetrics</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>BtreeIndexCounters</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>ConnectionMetrics</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>GlobalLoclMetrics</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>MemoryMetrics</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>OperationCounters</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>ServerInfo</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>MongoAdmin</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
|
||||
<para>This is shown below in a screenshot from JConsole</para> |
||||
|
||||
<mediaobject> |
||||
<imageobject> |
||||
<imagedata fileref="jconsole.png" /> |
||||
</imageobject> |
||||
</mediaobject> |
||||
</section> |
||||
</chapter> |
||||
@ -1,44 +0,0 @@
@@ -1,44 +0,0 @@
|
||||
<?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.logging"> |
||||
<title>Logging support</title> |
||||
|
||||
<para>An appender for Log4j is provided in the maven module |
||||
"spring-data-mongodb-log4j". Note, there is no dependency on other Spring |
||||
Mongo modules, only the MongoDB driver.</para> |
||||
|
||||
<section id="mongodb:logging-configuration"> |
||||
<title>MongoDB Log4j Configuration</title> |
||||
|
||||
<para>Here is an example configuration</para> |
||||
|
||||
<programlisting>log4j.rootCategory=INFO, stdout |
||||
|
||||
log4j.appender.stdout=org.springframework.data.document.mongodb.log4j.MongoLog4jAppender |
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout |
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n |
||||
log4j.appender.stdout.host = localhost |
||||
log4j.appender.stdout.port = 27017 |
||||
log4j.appender.stdout.database = logs |
||||
log4j.appender.stdout.collectionPattern = %X{year}%X{month} |
||||
log4j.appender.stdout.applicationId = my.application |
||||
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE |
||||
|
||||
log4j.category.org.apache.activemq=ERROR |
||||
log4j.category.org.springframework.batch=DEBUG |
||||
log4j.category.org.springframework.data.document.mongodb=DEBUG |
||||
log4j.category.org.springframework.transaction=INFO</programlisting> |
||||
|
||||
<para>The important configuration to look at aside from host and port is |
||||
the database and collectionPattern. The variables year, month, day and |
||||
hour are available for you to use in forming a collection name. This is to |
||||
support the common convention of grouping log information in a collection |
||||
that corresponds to a specific time period, for example a collection per |
||||
day.</para> |
||||
|
||||
<para>There is also an applicationId which is put into the stored message. |
||||
The document stored from logging as the following keys: level, name, |
||||
applicationId, timestamp, properties, traceback, and message. </para> |
||||
</section> |
||||
</chapter> |
||||
@ -1,744 +0,0 @@
@@ -1,744 +0,0 @@
|
||||
<?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="mapping-chapter"> |
||||
<title>Mapping</title> |
||||
|
||||
<para>Rich mapping support is provided by the |
||||
<classname>MongoMappingConverter</classname>. |
||||
<classname>MongoMappingConverter</classname> has a rich metadata model that |
||||
provides a full feature set of functionality to map domain objects to |
||||
MongoDB documents.The mapping metadata model is populated using annotations |
||||
on your domain objects. However, the infrastructure is not limited to using |
||||
annotations as the only source of metadata information. The |
||||
<classname>MongoMappingConverter</classname> also allows you to map objects |
||||
to documents without providing any additional metadata, by following a set |
||||
of conventions.</para> |
||||
|
||||
<para>In this section we will describe the features of the |
||||
MongoMappingConverter. How to use conventions for mapping objects to |
||||
documents and how to override those conventions with annotation based |
||||
mapping metadata.</para> |
||||
|
||||
<note> |
||||
<para><classname>SimpleMongoConverter</classname> has been deprecated in |
||||
Spring Data MongoDB M3 as all of its functionality has been subsumed into |
||||
<classname>MappingMongoConverter</classname>.</para> |
||||
</note> |
||||
|
||||
<section id="mapping-conventions"> |
||||
<title>Convention based Mapping</title> |
||||
|
||||
<para><classname>MongoMappingConverter</classname> has a few conventions |
||||
for mapping objects to documents when no additional mapping metadata is |
||||
provided. The conventions are:</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>The short Java class name is mapped to the collection name in |
||||
the following manner. The class |
||||
'<classname>com.bigbank.SavingsAccount</classname>' maps to |
||||
'<literal>savingsAccount</literal>' collection name.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>All nested objects are stored as nested objects in the document |
||||
and *not* as DBRefs</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>The converter will use any Spring Converters registered with it |
||||
to override the default mapping of object properties to document |
||||
field/values.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>The fields of an object are used to convert to and from fields |
||||
in the document. Public JavaBean properties are not used.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>You can have a single non-zero argument constructor whose |
||||
constructor argument names match top level field names of document, |
||||
that constructor will be used. Otherwise the zero arg constructor will |
||||
be used. if there is more than one non-zero argument constructor an |
||||
exception will be thrown.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
|
||||
<section id="mapping.conventions.id-field"> |
||||
<title>How the '_id' field is handled in the mapping layer</title> |
||||
|
||||
<para>MongoDB 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. The "_id" field can be of any type the, other than |
||||
arrays, so long as it is unique. The driver naturally supports all |
||||
primitive types and Dates. 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 field will be mapped to the '_id' |
||||
document field:</para> |
||||
|
||||
<para><itemizedlist> |
||||
<listitem> |
||||
<para>A 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 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.</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>If a field named 'id' is declared as a String or BigInteger in |
||||
the Java class it will be converted to and stored as an ObjectId if |
||||
possible. ObjectId as a field type is also valid. If you specify a |
||||
value for 'id' in your application, the conversion to an ObjectId is |
||||
detected to the MongoDBdriver. If the specified 'id' value cannot be |
||||
converted to an ObjectId, then the value will be stored as is in the |
||||
document's _id field.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>If a field named ' id' id field is not declared as a String, |
||||
BigInteger, or ObjectID in the Java class then you should assign it |
||||
a value in your application so it can be stored 'as-is' in the |
||||
document's _id field.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>If no field named 'id' 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> |
||||
</listitem> |
||||
</itemizedlist> |
||||
|
||||
<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> |
||||
|
||||
<section id="mapping-configuration"> |
||||
<title>Mapping Configuration</title> |
||||
|
||||
<para>Unless explicitly configured, an instance of |
||||
<classname>MongoMappingConverter</classname> is created by default when |
||||
creating a <classname>MongoTemplate</classname>. You can create your own |
||||
instance of the <classname>MappingMongoConverter</classname> so as to tell |
||||
it where to scan the classpath at startup your domain classes in order to |
||||
extract metadata and construct indexes. Also, by creating your own |
||||
instance you can register Spring converters to use for mapping specific |
||||
classes to and from the database.</para> |
||||
|
||||
<para>You can configure the <classname>MongoMappingConverter</classname> |
||||
as well as <classname>com.mongodb.Mongo</classname> and MongoTemplate |
||||
either using Java or XML based metadata. Here is an example using Spring's |
||||
Java based configuration</para> |
||||
|
||||
<example> |
||||
<title>@Configuration class to configure MongoDB mapping support</title> |
||||
|
||||
<programlisting language="java">@Configuration |
||||
public class GeoSpatialAppConfig extends AbstractMongoConfiguration { |
||||
|
||||
@Bean |
||||
public Mongo mongo() throws Exception { |
||||
return new Mongo("localhost"); |
||||
} |
||||
|
||||
@Override |
||||
public String getDatabaseName() { |
||||
return "database"; |
||||
} |
||||
|
||||
@Override |
||||
public String getMappingBasePackage() { |
||||
return "com.bigbank.domain"; |
||||
} |
||||
|
||||
// the following are optional |
||||
|
||||
|
||||
@Bean |
||||
@Override |
||||
public CustomConversions customConversions() throws Exception { |
||||
List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>(); |
||||
converterList.add(new org.springframework.data.mongodb.test.PersonReadConverter()); |
||||
converterList.add(new org.springframework.data.mongodb.test.PersonWriteConverter()); |
||||
return new CustomConversions(converterList); |
||||
} |
||||
|
||||
@Bean |
||||
public LoggingEventListener<MongoMappingEvent> mappingEventsListener() { |
||||
return new LoggingEventListener<MongoMappingEvent>(); |
||||
} |
||||
|
||||
}</programlisting> |
||||
</example> |
||||
|
||||
<para><classname>AbstractMongoConfiguration</classname> requires you to |
||||
implement methods that define a <classname>com.mongodb.Mongo</classname> |
||||
as well as provide a database name. |
||||
<classname>AbstractMongoConfiguration</classname> also has a method you |
||||
can override named '<methodname>getMappingBasePackage</methodname>' which |
||||
tells the converter where to scan for classes annotated with the |
||||
<classname>@org.springframework.data.mongodb.core.mapping.Document</classname> |
||||
annotation.</para> |
||||
|
||||
<para>You can add additional converters to the converter by overriding the |
||||
method afterMappingMongoConverterCreation. Also shown in the above example |
||||
is a <classname>LoggingEventListener</classname> which logs |
||||
<classname>MongoMappingEvent</classname>s that are posted onto Spring's |
||||
<interfacename>ApplicationContextEvent</interfacename> |
||||
infrastructure.</para> |
||||
|
||||
<note> |
||||
<para>AbstractMongoConfiguration will create a MongoTemplate instance |
||||
and registered with the container under the name 'mongoTemplate'.</para> |
||||
</note> |
||||
|
||||
<para>You can also override the method <literal>UserCredentials |
||||
getUserCredentials()</literal> to provide the username and password |
||||
information to connect to the database.</para> |
||||
|
||||
<para>Spring's MongoDB namespace enables you to easily enable mapping |
||||
functionality in XML</para> |
||||
|
||||
<example> |
||||
<title>XML schema to configure MongoDB mapping support</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 |
||||
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"/> |
||||
|
||||
<mongo:db-factory dbname="database" mongo-ref="mongo"/> |
||||
|
||||
<!-- by default look for a Mongo object named 'mongo' - default name used for the converter is 'mappingConverter' --> |
||||
<mongo:mapping-converter base-package="com.bigbank.domain"> |
||||
<mongo:custom-converters> |
||||
<mongo:converter ref="readConverter"/> |
||||
<mongo:converter> |
||||
<bean class="org.springframework.data.mongodb.test.PersonWriteConverter"/> |
||||
</mongo:converter> |
||||
</mongo:custom-converters> |
||||
</mongo:mapping-converter> |
||||
|
||||
<bean id="readConverter" class="org.springframework.data.mongodb.test.PersonReadConverter"/> |
||||
|
||||
<!-- set the mapping converter to be used by the MongoTemplate --> |
||||
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> |
||||
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> |
||||
<constructor-arg name="mongoConverter" ref="mappingConverter"/> |
||||
</bean> |
||||
|
||||
<bean class="org.springframework.data.mongodb.core.mapping.event.LoggingEventListener"/> |
||||
|
||||
</beans |
||||
</programlisting> |
||||
</example> |
||||
|
||||
<para>The <code>base-package</code> property tells it where to scan for |
||||
classes annotated with the |
||||
<classname>@org.springframework.data.mongodb.core.mapping.Document</classname> |
||||
annotation.</para> |
||||
</section> |
||||
|
||||
<section id="mapping-usage"> |
||||
<title>Metadata based Mapping</title> |
||||
|
||||
<para>To take full advantage of the object mapping functionality inside |
||||
the Spring Data/MongoDB support, you should annotate your mapped objects |
||||
with the |
||||
<classname>@org.springframework.data.mongodb.core.mapping.Document</classname> |
||||
annotation. Although it is not necessary for the mapping framework to have |
||||
this annotation (your POJOs will be mapped correctly, even without any |
||||
annotations), it allows the classpath scanner to find and pre-process your |
||||
domain objects to extract the necessary metadata. If you don't use this |
||||
annotation, your application will take a slight performance hit the first |
||||
time you store a domain object because the mapping framework needs to |
||||
build up its internal metadata model so it knows about the properties of |
||||
your domain object and how to persist them.</para> |
||||
|
||||
<example> |
||||
<title>Example domain object</title> |
||||
|
||||
<programlisting language="java">package com.mycompany.domain; |
||||
|
||||
@Document |
||||
public class Person { |
||||
|
||||
@Id |
||||
private ObjectId id; |
||||
|
||||
@Indexed |
||||
private Integer ssn; |
||||
|
||||
private String firstName; |
||||
|
||||
@Indexed |
||||
private String lastName; |
||||
|
||||
} |
||||
</programlisting> |
||||
</example> |
||||
|
||||
<important> |
||||
<para>The <classname>@Id</classname> annotation tells the mapper which |
||||
property you want to use for the MongoDB <code>_id</code> property and |
||||
the <classname>@Indexed</classname> annotation tells the mapping |
||||
framework to call <code>ensureIndex</code> on that property of your |
||||
document, making searches faster.</para> |
||||
</important> |
||||
|
||||
<important> |
||||
<para>Automatic index creation is only done for types annotated with |
||||
<classname>@Document</classname>.</para> |
||||
</important> |
||||
|
||||
<section id="mapping-usage-annotations"> |
||||
<title>Mapping annotation overview</title> |
||||
|
||||
<para>The MappingMongoConverter can use metadata to drive the mapping of |
||||
objects to documents. An overview of the annotations is provided |
||||
below</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para><literal>@Id </literal>- applied at the field level to mark |
||||
the field used for identiy purpose.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@Document</literal> - applied at the class level to |
||||
indicate this class is a candidate for mapping to the database. You |
||||
can specify the name of the collection where the database will be |
||||
stored.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@DBRef</literal> - applied at the field to indicate |
||||
it is to be stored using a com.mongodb.DBRef.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@Indexed</literal> - applied at the field level to |
||||
describe how to index the field.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@CompoundIndex</literal> - applied at the type level |
||||
to declare Compound Indexes</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@GeoSpatialIndexed</literal> - applied at the field |
||||
level to describe how to geoindex the field.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@TextIndexed</literal> - applied at the field level |
||||
to mark the field to be included in the text index.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@Language</literal> - applied at the field level to |
||||
set the language override property for text index.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@Transient</literal> - by default all private fields |
||||
are mapped to the document, this annotation excludes the field where |
||||
it is applied from being stored in the database</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@PersistenceConstructor</literal> - marks a given |
||||
constructor - even a package protected one - to use when |
||||
instantiating the object from the database. Constructor arguments |
||||
are mapped by name to the key values in the retrieved |
||||
DBObject.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@Value</literal> - this annotation is part of the |
||||
Spring Framework . Within the mapping framework it can be applied to |
||||
constructor arguments. This lets you use a Spring Expression |
||||
Language statement to transform a key's value retrieved in the |
||||
database before it is used to construct a domain object. In order to |
||||
reference a property of a given document one has to use expressions |
||||
like: <code>@Value("#root.myProperty")</code> where |
||||
<literal>root</literal> refers to the root of the given |
||||
document.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para><literal>@Field</literal> - applied at the field level and |
||||
described the name of the field as it will be represented in the |
||||
MongoDB BSON document thus allowing the name to be different than |
||||
the fieldname of the class.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
|
||||
<para>The mapping metadata infrastructure is defined in a seperate |
||||
spring-data-commons project that is technology agnostic. Specific |
||||
subclasses are using in the MongoDB support to support annotation based |
||||
metadata. Other strategies are also possible to put in place if there is |
||||
demand.</para> |
||||
|
||||
<para>Here is an example of a more complex mapping.</para> |
||||
|
||||
<programlisting language="java">@Document |
||||
@CompoundIndexes({ |
||||
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}") |
||||
}) |
||||
public class Person<T extends Address> { |
||||
|
||||
@Id |
||||
private String id; |
||||
|
||||
@Indexed(unique = true) |
||||
private Integer ssn; |
||||
|
||||
@Field("fName") |
||||
private String firstName; |
||||
|
||||
@Indexed |
||||
private String lastName; |
||||
|
||||
private Integer age; |
||||
|
||||
@Transient |
||||
private Integer accountTotal; |
||||
|
||||
@DBRef |
||||
private List<Account> accounts; |
||||
|
||||
private T address; |
||||
|
||||
|
||||
public Person(Integer ssn) { |
||||
this.ssn = ssn; |
||||
} |
||||
|
||||
@PersistenceConstructor |
||||
public Person(Integer ssn, String firstName, String lastName, Integer age, T address) { |
||||
this.ssn = ssn; |
||||
this.firstName = firstName; |
||||
this.lastName = lastName; |
||||
this.age = age; |
||||
this.address = address; |
||||
} |
||||
|
||||
public String getId() { |
||||
return id; |
||||
} |
||||
|
||||
// no setter for Id. (getter is only exposed for some unit testing) |
||||
|
||||
public Integer getSsn() { |
||||
return ssn; |
||||
} |
||||
|
||||
|
||||
// other getters/setters ommitted |
||||
</programlisting> |
||||
|
||||
<para/> |
||||
</section> |
||||
|
||||
<section id="mapping-custom-object-construction"> |
||||
<title>Customized Object Construction</title> |
||||
|
||||
<para>The mapping subsystem allows the customization of the object |
||||
construction by annotating a constructor with the |
||||
<literal>@PersistenceConstructor</literal> annotation. The values to be |
||||
used for the constructor parameters are resolved in the following |
||||
way:</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>If a parameter is annotated with the <code>@Value</code> |
||||
annotation, the given expression is evaluated and the result is used |
||||
as the parameter value.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>If the Java type has a property whose name matches the given |
||||
field of the input document, then it's property information is used |
||||
to select the appropriate constructor parameter to pass the input |
||||
field value to. This works only if the parameter name information is |
||||
present in the java .class files which can be achieved by compiling |
||||
the source with debug information or using the new |
||||
<literal>-parameters</literal> command-line switch for javac in Java |
||||
8.</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>Otherwise an <classname>MappingException</classname> will be |
||||
thrown indicating that the given constructor parameter could not be |
||||
bound.</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
|
||||
<programlisting language="java">class OrderItem { |
||||
|
||||
private @Id String id; |
||||
private int quantity; |
||||
private double unitPrice; |
||||
|
||||
OrderItem(String id, @Value("#root.qty ?: 0") int quantity, double unitPrice) { |
||||
this.id = id; |
||||
this.quantity = quantity; |
||||
this.unitPrice = unitPrice; |
||||
} |
||||
|
||||
// getters/setters ommitted |
||||
} |
||||
|
||||
DBObject input = new BasicDBObject("id", "4711"); |
||||
input.put("unitPrice", 2.5); |
||||
input.put("qty",5); |
||||
OrderItem item = converter.read(OrderItem.class, input);</programlisting> |
||||
|
||||
<note> |
||||
<para>The SpEL expression in the <literal>@Value</literal> annotation |
||||
of the <literal>quantity</literal> parameter falls back to the value |
||||
<literal>0</literal> if the given property path cannot be |
||||
resolved.</para> |
||||
</note> |
||||
|
||||
<para>Additional examples for using the |
||||
<classname>@PersistenceConstructor</classname> annotation can be found |
||||
in the <ulink |
||||
url="https://github.com/spring-projects/spring-data-mongodb/blob/master/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java">MappingMongoConverterUnitTests</ulink> |
||||
test suite.</para> |
||||
</section> |
||||
|
||||
<section id="mapping-usage-indexes.compound-index"> |
||||
<title>Compound Indexes</title> |
||||
|
||||
<para>Compound indexes are also supported. They are defined at the class |
||||
level, rather than on indidvidual properties.</para> |
||||
|
||||
<note> |
||||
<para>Compound indexes are very important to improve the performance |
||||
of queries that involve criteria on multiple fields</para> |
||||
</note> |
||||
|
||||
<para>Here's an example that creates a compound index of |
||||
<code>lastName</code> in ascending order and <code>age</code> in |
||||
descending order: <example> |
||||
<title>Example Compound Index Usage</title> |
||||
|
||||
<programlisting language="java">package com.mycompany.domain; |
||||
|
||||
@Document |
||||
@CompoundIndexes({ |
||||
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}") |
||||
}) |
||||
public class Person { |
||||
|
||||
@Id |
||||
private ObjectId id; |
||||
private Integer age; |
||||
private String firstName; |
||||
private String lastName; |
||||
|
||||
} |
||||
</programlisting> |
||||
</example></para> |
||||
</section> |
||||
|
||||
<section id="mapping-usage-indexes.text-index"> |
||||
<title>Text Indexes</title> |
||||
|
||||
<note> |
||||
<para>The text index feature is disabled by default for mongodb |
||||
v.2.4.</para> |
||||
</note> |
||||
|
||||
<para>Creating a text index allows to accumulate several fields into a |
||||
searchable full text index. It is only possible to have one text index |
||||
per collection so all fields marked with |
||||
<interfacename>@TextIndexed</interfacename> are combined into this |
||||
index. Properties can be weighted to influence document score for |
||||
ranking results. The default language for the text index is english, to |
||||
change the default language set |
||||
<interfacename>@Document(language="spanish")</interfacename> to any |
||||
language you want. Using a property called <literal>language</literal> |
||||
or <interfacename>@Language</interfacename> allows to define a language |
||||
override on a per document base.</para> |
||||
|
||||
<example> |
||||
<title>Example Text Index Usage</title> |
||||
|
||||
<programlisting language="java">@Document(language = "spanish") |
||||
class SomeEntity { |
||||
|
||||
@TextIndexed String foo; |
||||
|
||||
@Language String lang; |
||||
|
||||
Nested nested; |
||||
|
||||
|
||||
} |
||||
|
||||
class Nested { |
||||
|
||||
@TextIndexed(weight=5) String bar; |
||||
|
||||
String roo; |
||||
} |
||||
</programlisting> |
||||
</example> |
||||
</section> |
||||
|
||||
<section id="mapping-usage-references"> |
||||
<title>Using DBRefs</title> |
||||
|
||||
<para>The mapping framework doesn't have to store child objects embedded |
||||
within the document. You can also store them separately and use a DBRef |
||||
to refer to that document. When the object is loaded from MongoDB, those |
||||
references will be eagerly resolved and you will get back a mapped |
||||
object that looks the same as if it had been stored embedded within your |
||||
master document.</para> |
||||
|
||||
<para>Here's an example of using a DBRef to refer to a specific document |
||||
that exists independently of the object in which it is referenced (both |
||||
classes are shown in-line for brevity's sake):</para> |
||||
|
||||
<example> |
||||
<programlisting language="java"> |
||||
@Document |
||||
public class Account { |
||||
|
||||
@Id |
||||
private ObjectId id; |
||||
private Float total; |
||||
|
||||
} |
||||
|
||||
@Document |
||||
public class Person { |
||||
|
||||
@Id |
||||
private ObjectId id; |
||||
@Indexed |
||||
private Integer ssn; |
||||
@DBRef |
||||
private List<Account> accounts; |
||||
|
||||
} |
||||
</programlisting> |
||||
</example> |
||||
|
||||
<para>There's no need to use something like <code>@OneToMany</code> |
||||
because the mapping framework sees that you're wanting a one-to-many |
||||
relationship because there is a List of objects. When the object is |
||||
stored in MongoDB, there will be a list of DBRefs rather than the |
||||
<code>Account</code> objects themselves. <important> |
||||
<para>The mapping framework does not handle cascading saves. If you |
||||
change an <code>Account</code> object that is referenced by a |
||||
<code>Person</code> object, you must save the Account object |
||||
separately. Calling <code>save</code> on the <code>Person</code> |
||||
object will not automatically save the <code>Account</code> objects |
||||
in the property <code>accounts</code>.</para> |
||||
</important></para> |
||||
</section> |
||||
|
||||
<section id="mapping-usage-events"> |
||||
<title>Mapping Framework Events</title> |
||||
|
||||
<para>Events are fired throughout the lifecycle of the mapping process. |
||||
This is described in the <link |
||||
linkend="mongodb.mapping-usage.events">Lifecycle Events</link> |
||||
section.</para> |
||||
|
||||
<para>Simply declaring these beans in your Spring ApplicationContext |
||||
will cause them to be invoked whenever the event is dispatched.</para> |
||||
</section> |
||||
|
||||
<section id="mapping-explicit-converters"> |
||||
<title>Overriding Mapping with explicit Converters</title> |
||||
|
||||
<para>When storing and querying your objects it is convenient to have a |
||||
<interfacename>MongoConverter</interfacename> instance handle the |
||||
mapping of all Java types to DBObjects. However, sometimes you may want |
||||
the <interfacename>MongoConverter</interfacename>'s do most of the work |
||||
but allow you to selectivly handle the conversion for a particular type |
||||
or to optimize performance.</para> |
||||
|
||||
<para>To selectivly handle the conversion yourself, register one or more |
||||
one or more |
||||
<classname>org.springframework.core.convert.converter.Converter</classname> |
||||
instances with the MongoConverter.</para> |
||||
|
||||
<note> |
||||
<para>Spring 3.0 introduced a core.convert package that provides a |
||||
general type conversion system. This is described in detail in the |
||||
Spring reference documentation section entitled <ulink |
||||
url="http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html#core-convert">Spring |
||||
3 Type Conversion</ulink>.</para> |
||||
</note> |
||||
|
||||
<para>The method <methodname>customConversions</methodname> in |
||||
<classname>AbstractMongoConfiguration</classname> can be used to |
||||
configure Converters. The examples <link |
||||
linkend="mapping-configuration">here</link> at the begining of this |
||||
chapter show how to perform the configuration using Java and XML.</para> |
||||
|
||||
<para>Below is an example of a Spring Converter implementation that |
||||
converts from a DBObject to a Person POJO.</para> |
||||
|
||||
<programlisting language="java">@ReadingConverter |
||||
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> |
||||
|
||||
<para>Here is an example that converts from a Person to a |
||||
DBObject.</para> |
||||
|
||||
<programlisting language="java">@WritingConverter |
||||
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> |
||||
</chapter> |
||||
@ -1,652 +0,0 @@
@@ -1,652 +0,0 @@
|
||||
<?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.repositories"> |
||||
<title>MongoDB repositories</title> |
||||
|
||||
<section id="mongo-repo-intro"> |
||||
<title>Introduction</title> |
||||
|
||||
<para>This chapter will point out the specialties for repository support |
||||
for MongoDB. This builds on the core repository support explained in <xref |
||||
linkend="repositories"/>. So make sure you've got a sound understanding of |
||||
the basic concepts explained there.</para> |
||||
</section> |
||||
|
||||
<section id="mongo-repo-usage"> |
||||
<title>Usage</title> |
||||
|
||||
<para>To access domain entities stored in a MongoDB you can leverage our |
||||
sophisticated repository support that eases implementing those quite |
||||
significantly. To do so, simply create an interface for your |
||||
repository:</para> |
||||
|
||||
<example> |
||||
<title>Sample Person entity</title> |
||||
|
||||
<programlisting language="java">public class Person { |
||||
|
||||
@Id |
||||
private String id; |
||||
private String firstname; |
||||
private String lastname; |
||||
private Address address; |
||||
|
||||
// … getters and setters omitted |
||||
} |
||||
</programlisting> |
||||
</example> |
||||
|
||||
<para>We have a quite simple domain object here. Note that it has a |
||||
property named <code>id</code> of type<classname>ObjectId</classname>. The |
||||
default serialization mechanism used in |
||||
<classname>MongoTemplate</classname> (which is backing the repository |
||||
support) regards properties named id as document id. Currently we |
||||
support<classname>String</classname>, <classname>ObjectId</classname> and |
||||
<classname>BigInteger</classname> as id-types.</para> |
||||
|
||||
<example> |
||||
<title>Basic repository interface to persist Person entities</title> |
||||
|
||||
<programlisting>public interface PersonRepository extends PagingAndSortingRepository<Person, Long> { |
||||
|
||||
// additional custom finder methods go here |
||||
} |
||||
</programlisting> |
||||
</example> |
||||
|
||||
<para>Right now this interface simply serves typing purposes but we will |
||||
add additional methods to it later. In your Spring configuration simply |
||||
add</para> |
||||
|
||||
<example> |
||||
<title>General MongoDB repository Spring configuration</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:mongo="http://www.springframework.org/schema/data/mongo" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans |
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd |
||||
http://www.springframework.org/schema/data/mongo |
||||
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"> |
||||
|
||||
<mongo:mongo id="mongo" /> |
||||
|
||||
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> |
||||
<constructor-arg ref="mongo" /> |
||||
<constructor-arg value="databaseName" /> |
||||
</bean> |
||||
|
||||
<mongo:repositories base-package="com.acme.*.repositories" /> |
||||
|
||||
</beans></programlisting> |
||||
</example> |
||||
|
||||
<para>This namespace element will cause the base packages to be scanned |
||||
for interfaces extending <interfacename>MongoRepository</interfacename> |
||||
and create Spring beans for each of them found. By default the |
||||
repositories will get a <classname>MongoTemplate</classname> Spring bean |
||||
wired that is called <code>mongoTemplate</code>, so you only need to |
||||
configure <code>mongo-template-ref</code> explicitly if you deviate from |
||||
this convention.</para> |
||||
|
||||
<para>If you'd rather like to go with JavaConfig use the |
||||
<interfacename>@EnableMongoRepositories</interfacename> annotation. The |
||||
annotation carries the very same attributes like the namespace element. If |
||||
no base package is configured the infrastructure will scan the package of |
||||
the annotated configuration class.</para> |
||||
|
||||
<example> |
||||
<title>JavaConfig for repositories</title> |
||||
|
||||
<programlisting id="id2371855_07-mongodb" language="java">@Configuration |
||||
@EnableMongoRepositories |
||||
class ApplicationConfig extends AbstractMongoConfiguration { |
||||
|
||||
@Override |
||||
protected String getDatabaseName() { |
||||
return "e-store"; |
||||
} |
||||
|
||||
@Override |
||||
public Mongo mongo() throws Exception { |
||||
return new Mongo(); |
||||
} |
||||
|
||||
@Override |
||||
protected String getMappingBasePackage() { |
||||
return "com.oreilly.springdata.mongodb" |
||||
} |
||||
}</programlisting> |
||||
</example> |
||||
|
||||
<para>As our domain repository extends |
||||
<interfacename>PagingAndSortingRepository</interfacename> it provides you |
||||
with CRUD operations as well as methods for paginated and sorted access to |
||||
the entities. Working with the repository instance is just a matter of |
||||
dependency injecting it into a client. So accessing the second page of |
||||
<classname>Person</classname>s at a page size of 10 would simply look |
||||
something like this:</para> |
||||
|
||||
<example> |
||||
<title>Paging access to Person entities</title> |
||||
|
||||
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
||||
@ContextConfiguration |
||||
public class PersonRepositoryTests { |
||||
|
||||
@Autowired PersonRepository repository; |
||||
|
||||
@Test |
||||
public void readsFirstPageCorrectly() { |
||||
|
||||
Page<Person> persons = repository.findAll(new PageRequest(0, 10)); |
||||
assertThat(persons.isFirstPage(), is(true)); |
||||
} |
||||
} </programlisting> |
||||
</example> |
||||
|
||||
<para>The sample creates an application context with Spring's unit test |
||||
support which will perform annotation based dependency injection into test |
||||
cases. Inside the test method we simply use the repository to query the |
||||
datastore. We hand the repository a <classname>PageRequest</classname> |
||||
instance that requests the first page of persons at a page size of |
||||
10.</para> |
||||
</section> |
||||
|
||||
<section id="mongodb.repositories.queries"> |
||||
<title>Query methods</title> |
||||
|
||||
<para>Most of the data access operations you usually trigger on a |
||||
repository result a query being executed against the MongoDB databases. |
||||
Defining such a query is just a matter of declaring a method on the |
||||
repository interface</para> |
||||
|
||||
<example> |
||||
<title>PersonRepository with query methods</title> |
||||
|
||||
<programlisting language="java">public interface PersonRepository extends PagingAndSortingRepository<Person, String> { |
||||
|
||||
List<Person> findByLastname(String lastname); |
||||
|
||||
Page<Person> findByFirstname(String firstname, Pageable pageable); |
||||
|
||||
Person findByShippingAddresses(Address address); |
||||
|
||||
} </programlisting> |
||||
</example> |
||||
|
||||
<para>The first method shows a query for all people with the given |
||||
lastname. The query will be derived parsing the method name for |
||||
constraints which can be concatenated with <literal>And</literal> and |
||||
<literal>Or</literal>. Thus the method name will result in a query |
||||
expression of<code>{"lastname" : lastname}</code>. The second example |
||||
shows how pagination is applied to a query. Just equip your method |
||||
signature with a <interfacename>Pageable</interfacename> parameter and let |
||||
the method return a <interfacename>Page</interfacename> instance and we |
||||
will automatically page the query accordingly. The third examples shows |
||||
that you can query based on properties which are not a primitive |
||||
type.</para> |
||||
|
||||
<note> |
||||
<para>Note that for version 1.0 we currently don't support referring to |
||||
parameters that are mapped as <classname>DBRef</classname> in the domain |
||||
class.</para> |
||||
</note> |
||||
|
||||
<para><table> |
||||
<title>Supported keywords for query methods</title> |
||||
|
||||
<tgroup cols="3"> |
||||
<colspec colwidth="1*"/> |
||||
|
||||
<colspec colwidth="2*"/> |
||||
|
||||
<colspec colwidth="2*"/> |
||||
|
||||
<thead> |
||||
<row> |
||||
<entry>Keyword</entry> |
||||
|
||||
<entry>Sample</entry> |
||||
|
||||
<entry>Logical result</entry> |
||||
</row> |
||||
</thead> |
||||
|
||||
<tbody> |
||||
<row> |
||||
<entry><literal>GreaterThan</literal></entry> |
||||
|
||||
<entry><methodname>findByAgeGreaterThan(int |
||||
age)</methodname></entry> |
||||
|
||||
<entry><code>{"age" : {"$gt" : age}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>GreaterThanEqual</literal></entry> |
||||
|
||||
<entry><methodname>findByAgeGreaterThanEqual(int |
||||
age)</methodname></entry> |
||||
|
||||
<entry><code>{"age" : {"$gte" : age}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>LessThan</literal></entry> |
||||
|
||||
<entry><methodname>findByAgeLessThan(int |
||||
age)</methodname></entry> |
||||
|
||||
<entry><code>{"age" : {"$lt" : age}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>LessThanEqual</literal></entry> |
||||
|
||||
<entry><methodname>findByAgeLessThanEqual(int |
||||
age)</methodname></entry> |
||||
|
||||
<entry><code>{"age" : {"$lte" : age}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>Between</literal></entry> |
||||
|
||||
<entry><methodname>findByAgeBetween(int from, int |
||||
to)</methodname></entry> |
||||
|
||||
<entry><code>{"age" : {"$gt" : from, "$lt" : to}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>In</literal></entry> |
||||
|
||||
<entry><methodname>findByAgeIn(Collection ages) |
||||
</methodname></entry> |
||||
|
||||
<entry><code>{"age" : {"$in" : [ages...]}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>NotIn</literal></entry> |
||||
|
||||
<entry><methodname>findByAgeNotIn(Collection ages) |
||||
</methodname></entry> |
||||
|
||||
<entry><code>{"age" : {"$nin" : [ages...]}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>IsNotNull</literal>, |
||||
<literal>NotNull</literal></entry> |
||||
|
||||
<entry><methodname>findByFirstnameNotNull()</methodname></entry> |
||||
|
||||
<entry><code>{"age" : {"$ne" : null}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>IsNull</literal>, |
||||
<literal>Null</literal></entry> |
||||
|
||||
<entry><methodname>findByFirstnameNull()</methodname></entry> |
||||
|
||||
<entry><code>{"age" : null}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>Like</literal></entry> |
||||
|
||||
<entry><methodname>findByFirstnameLike(String |
||||
name)</methodname></entry> |
||||
|
||||
<entry><code>{"age" : age}</code> ( <varname>age</varname> as |
||||
regex)</entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>Regex</literal></entry> |
||||
|
||||
<entry><methodname>findByFirstnameRegex(String |
||||
firstname)</methodname></entry> |
||||
|
||||
<entry><code>{"firstname" : {"$regex" : firstname |
||||
}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry>(No keyword)</entry> |
||||
|
||||
<entry><methodname>findByFirstname(String |
||||
name)</methodname></entry> |
||||
|
||||
<entry><code>{"age" : name}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>Not</literal></entry> |
||||
|
||||
<entry><methodname>findByFirstnameNot(String |
||||
name)</methodname></entry> |
||||
|
||||
<entry><code>{"age" : {"$ne" : name}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>Near</literal></entry> |
||||
|
||||
<entry><methodname>findByLocationNear(Point |
||||
point)</methodname></entry> |
||||
|
||||
<entry><code>{"location" : {"$near" : [x,y]}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>Within</literal></entry> |
||||
|
||||
<entry><methodname>findByLocationWithin(Circle |
||||
circle)</methodname></entry> |
||||
|
||||
<entry><code>{"location" : {"$within" : {"$center" : [ [x, y], |
||||
distance]}}}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>Within</literal></entry> |
||||
|
||||
<entry><methodname>findByLocationWithin(Box |
||||
box)</methodname></entry> |
||||
|
||||
<entry><code>{"location" : {"$within" : {"$box" : [ [x1, y1], |
||||
x2, y2]}}}True</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>IsTrue</literal>, |
||||
<literal>True</literal></entry> |
||||
|
||||
<entry><code>findByActiveIsTrue()</code></entry> |
||||
|
||||
<entry><code>{"active" : true}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>IsFalse</literal>, |
||||
<literal>False</literal></entry> |
||||
|
||||
<entry><code>findByActiveIsFalse()</code></entry> |
||||
|
||||
<entry><code>{"active" : false}</code></entry> |
||||
</row> |
||||
|
||||
<row> |
||||
<entry><literal>Exists</literal></entry> |
||||
|
||||
<entry><methodname>findByLocationExists(boolean |
||||
exists)</methodname></entry> |
||||
|
||||
<entry><code>{"location" : {"$exists" : exists }}</code></entry> |
||||
</row> |
||||
</tbody> |
||||
</tgroup> |
||||
</table></para> |
||||
|
||||
<section id="mongodb.repositories.queries.delete"> |
||||
<title>Repository delete queries</title> |
||||
|
||||
<para>The above keywords can be used in conjunciton with |
||||
<code>delete…By</code> or <code>remove…By</code> to create queries |
||||
deleting matching documents.</para> |
||||
|
||||
<example> |
||||
<title><code>Delete…By</code> Query</title> |
||||
|
||||
<programlisting language="java">public interface PersonRepository extends MongoRepository<Person, String> { |
||||
List <Person> deleteByLastname(String lastname); |
||||
|
||||
Long deletePersonByLastname(String lastname); |
||||
}</programlisting> |
||||
</example> |
||||
|
||||
<para>Using return type <interfacename>List</interfacename> will |
||||
retrieve and return all matching documents before actually deleting |
||||
them. A numeric return type directly removes the matching documents |
||||
returning the total number of documents removed.</para> |
||||
</section> |
||||
|
||||
<section id="mongodb.repositories.queries.geo-spatial"> |
||||
<title>Geo-spatial repository queries</title> |
||||
|
||||
<para>As you've just seen there are a few keywords triggering |
||||
geo-spatial operations within a MongoDB query. The <code>Near</code> |
||||
keyword allows some further modification. Let's have look at some |
||||
examples:</para> |
||||
|
||||
<example> |
||||
<title>Advanced <code>Near</code> queries</title> |
||||
|
||||
<programlisting language="java">public interface PersonRepository extends MongoRepository<Person, String> |
||||
|
||||
// { 'location' : { '$near' : [point.x, point.y], '$maxDistance' : distance}} |
||||
List<Person> findByLocationNear(Point location, Distance distance); |
||||
}</programlisting> |
||||
</example> |
||||
|
||||
<para>Adding a <classname>Distance</classname> parameter to the query |
||||
method allows restricting results to those within the given distance. If |
||||
the <classname>Distance</classname> was set up containing a |
||||
<interfacename>Metric</interfacename> we will transparently use |
||||
<code>$nearSphere</code> instead of $code.</para> |
||||
|
||||
<example> |
||||
<title>Using <code>Distance</code> with <code>Metrics</code></title> |
||||
|
||||
<programlisting language="java">Point point = new Point(43.7, 48.8); |
||||
Distance distance = new Distance(200, Metrics.KILOMETERS); |
||||
… = repository.findByLocationNear(point, distance); |
||||
// {'location' : {'$nearSphere' : [43.7, 48.8], '$maxDistance' : 0.03135711885774796}}</programlisting> |
||||
</example> |
||||
|
||||
<para>As you can see using a <classname>Distance</classname> equipped |
||||
with a <interfacename>Metric</interfacename> causes |
||||
<code>$nearSphere</code> clause to be added instead of a plain |
||||
<code>$near</code>. Beyond that the actual distance gets calculated |
||||
according to the <classname>Metrics</classname> used.</para> |
||||
|
||||
<simplesect> |
||||
<title>Geo-near queries</title> |
||||
|
||||
<para/> |
||||
|
||||
<programlisting language="java">public interface PersonRepository extends MongoRepository<Person, String> |
||||
|
||||
// {'geoNear' : 'location', 'near' : [x, y] } |
||||
GeoResults<Person> findByLocationNear(Point location); |
||||
|
||||
// No metric: {'geoNear' : 'person', 'near' : [x, y], maxDistance : distance } |
||||
// Metric: {'geoNear' : 'person', 'near' : [x, y], 'maxDistance' : distance, |
||||
// 'distanceMultiplier' : metric.multiplier, 'spherical' : true } |
||||
GeoResults<Person> findByLocationNear(Point location, Distance distance); |
||||
|
||||
// {'geoNear' : 'location', 'near' : [x, y] } |
||||
GeoResults<Person> findByLocationNear(Point location); |
||||
}</programlisting> |
||||
</simplesect> |
||||
</section> |
||||
|
||||
<section id="mongodb.repositories.queries.json-based"> |
||||
<title>MongoDB JSON based query methods and field restriction</title> |
||||
|
||||
<para>By adding the annotation |
||||
<classname>org.springframework.data.mongodb.repository.Query</classname> |
||||
repository finder methods you can specify a MongoDB JSON query string to |
||||
use instead of having the query derived from the method name. For |
||||
example</para> |
||||
|
||||
<programlisting language="java">public interface PersonRepository extends MongoRepository<Person, String> |
||||
|
||||
@Query("{ 'firstname' : ?0 }") |
||||
List<Person> findByThePersonsFirstname(String firstname); |
||||
|
||||
}</programlisting> |
||||
|
||||
<para>The placeholder ?0 lets you substitute the value from the method |
||||
arguments into the JSON query string.</para> |
||||
|
||||
<para>You can also use the filter property to restrict the set of |
||||
properties that will be mapped into the Java object. For example,</para> |
||||
|
||||
<programlisting language="java">public interface PersonRepository extends MongoRepository<Person, String> |
||||
|
||||
@Query(value="{ 'firstname' : ?0 }", fields="{ 'firstname' : 1, 'lastname' : 1}") |
||||
List<Person> findByThePersonsFirstname(String firstname); |
||||
|
||||
}</programlisting> |
||||
|
||||
<para>This will return only the firstname, lastname and Id properties of |
||||
the Person objects. The age property, a java.lang.Integer, will not be |
||||
set and its value will therefore be null.</para> |
||||
</section> |
||||
|
||||
<section id="mongodb.repositories.queries.type-safe"> |
||||
<title>Type-safe Query methods</title> |
||||
|
||||
<para>MongoDB repository support integrates with the <ulink |
||||
url="http://www.querydsl.com/">QueryDSL</ulink> project which provides a |
||||
means to perform type-safe queries in Java. To quote from the project |
||||
description, "Instead of writing queries as inline strings or |
||||
externalizing them into XML files they are constructed via a fluent |
||||
API." It provides the following features</para> |
||||
|
||||
<itemizedlist> |
||||
<listitem> |
||||
<para>Code completion in IDE (all properties, methods and operations |
||||
can be expanded in your favorite Java IDE)</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>Almost no syntactically invalid queries allowed (type-safe on |
||||
all levels)</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>Domain types and properties can be referenced safely (no |
||||
Strings involved!)</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>Adopts better to refactoring changes in domain types</para> |
||||
</listitem> |
||||
|
||||
<listitem> |
||||
<para>Incremental query definition is easier</para> |
||||
</listitem> |
||||
</itemizedlist> |
||||
|
||||
<para>Please refer to the QueryDSL documentation which describes how to |
||||
bootstrap your environment for APT based code generation <ulink |
||||
url="http://source.mysema.com/static/querydsl/2.1.2/reference/html/ch02.html#d0e112">using |
||||
Maven</ulink> or <ulink |
||||
url="http://source.mysema.com/static/querydsl/2.1.2/reference/html/ch02.html#d0e131">using |
||||
Ant</ulink>.</para> |
||||
|
||||
<para>Using QueryDSL you will be able to write queries as shown |
||||
below</para> |
||||
|
||||
<programlisting language="java">QPerson person = new QPerson("person"); |
||||
List<Person> result = repository.findAll(person.address.zipCode.eq("C0123")); |
||||
|
||||
Page<Person> page = repository.findAll(person.lastname.contains("a"), |
||||
new PageRequest(0, 2, Direction.ASC, "lastname"));</programlisting> |
||||
|
||||
<para><classname>QPerson</classname> is a class that is generated (via |
||||
the Java annotation post processing tool) which is a |
||||
<classname>Predicate</classname> that allows you to write type safe |
||||
queries. Notice that there are no strings in the query other than the |
||||
value "C0123".</para> |
||||
|
||||
<para>You can use the generated <classname>Predicate</classname> class |
||||
via the interface |
||||
<interfacename>QueryDslPredicateExecutor</interfacename> which is shown |
||||
below</para> |
||||
|
||||
<programlisting language="java">public interface QueryDslPredicateExecutor<T> { |
||||
|
||||
T findOne(Predicate predicate); |
||||
|
||||
List<T> findAll(Predicate predicate); |
||||
|
||||
List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders); |
||||
|
||||
Page<T> findAll(Predicate predicate, Pageable pageable); |
||||
|
||||
Long count(Predicate predicate); |
||||
} |
||||
</programlisting> |
||||
|
||||
<para>To use this in your repository implementation, simply inherit from |
||||
it in addition to other repository interfaces. This is shown |
||||
below</para> |
||||
|
||||
<programlisting lang="" language="java">public interface PersonRepository extends MongoRepository<Person, String>, QueryDslPredicateExecutor<Person> { |
||||
|
||||
// additional finder methods go here |
||||
|
||||
}</programlisting> |
||||
|
||||
<para>We think you will find this an extremely powerful tool for writing |
||||
MongoDB queries.</para> |
||||
</section> |
||||
</section> |
||||
|
||||
<section id="mongodb.repositories.misc"> |
||||
<title>Miscellaneous</title> |
||||
|
||||
<para/> |
||||
|
||||
<section id="mongodb.repositories.misc.cdi-integration"> |
||||
<title>CDI Integration</title> |
||||
|
||||
<para>Instances of the repository interfaces are usually created by a |
||||
container, which Spring is the most natural choice when working with |
||||
Spring Data. As of version 1.3.0 Spring Data MongoDB ships with a custom |
||||
CDI extension that allows using the repository abstraction in CDI |
||||
environments. The extension is part of the JAR so all you need to do to |
||||
activate it is dropping the Spring Data MongoDB JAR into your classpath. |
||||
You can now set up the infrastructure by implementing a CDI Producer for |
||||
the <classname>MongoTemplate</classname>:</para> |
||||
|
||||
<programlisting language="java">class MongoTemplateProducer { |
||||
|
||||
@Produces |
||||
@ApplicationScoped |
||||
public MongoOperations createMongoTemplate() throws UnknownHostException, MongoException { |
||||
|
||||
MongoDbFactory factory = new SimpleMongoDbFactory(new Mongo(), "database"); |
||||
return new MongoTemplate(factory); |
||||
} |
||||
}</programlisting> |
||||
|
||||
<para>The Spring Data MongoDB CDI extension will pick up the |
||||
<classname>MongoTemplate</classname> available as CDI bean and create a |
||||
proxy for a Spring Data repository whenever an bean of a repository type |
||||
is requested by the container. Thus obtaining an instance of a Spring |
||||
Data repository is a matter of declaring an <code>@Inject</code>-ed |
||||
property:</para> |
||||
|
||||
<programlisting language="java">class RepositoryClient { |
||||
|
||||
@Inject |
||||
PersonRepository repository; |
||||
|
||||
public void businessMethod() { |
||||
|
||||
List<Person> people = repository.findAll(); |
||||
} |
||||
}</programlisting> |
||||
</section> |
||||
</section> |
||||
</chapter> |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
= Spring Data MongoDB - Reference Documentation |
||||
Mark Pollack, Thomas Risberg, Oliver Gierke, Costin Leau, Jon Brisbin, Thomas Darimont, Christoph Strobl |
||||
:toc: |
||||
:spring-data-commons-docs: https://raw.githubusercontent.com/spring-projects/spring-data-commons/issue/DATACMNS-551/src/main/asciidoc |
||||
{version} |
||||
|
||||
NOTE: _Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically._ |
||||
|
||||
include::preface.adoc[] |
||||
include::introduction/introduction.adoc[] |
||||
|
||||
:leveloffset: 1 |
||||
include::introduction/requirements.adoc[] |
||||
include::introduction/getting-started.adoc[] |
||||
include::{spring-data-commons-docs}/repositories.adoc[] |
||||
|
||||
:leveloffset: 0 |
||||
[[reference]] |
||||
= Reference Documentation |
||||
|
||||
:leveloffset: 1 |
||||
include::reference/introduction.adoc[] |
||||
include::reference/mongodb.adoc[] |
||||
include::reference/mongo-repositories.adoc[] |
||||
include::{spring-data-commons-docs}/auditing.adoc[] |
||||
include::reference/mapping.adoc[] |
||||
include::reference/cross-store.adoc[] |
||||
include::reference/logging.adoc[] |
||||
include::reference/jmx.adoc[] |
||||
|
||||
:leveloffset: 0 |
||||
= Appendix |
||||
|
||||
:numbered!: |
||||
:leveloffset: 1 |
||||
include::{spring-data-commons-docs}/repository-namespace-reference.adoc[] |
||||
include::{spring-data-commons-docs}/repository-namespace-reference.adoc[] |
||||
include::{spring-data-commons-docs}/repository-query-keywords-reference.adoc[] |
||||
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
[[get-started]] |
||||
= Additional Help Resources |
||||
|
||||
Learning a new framework is not always straight forward. In this section, we try to provide what we think is an easy to follow guide for starting with Spring Data Document module. However, if you encounter issues or you are just looking for an advice, feel free to use one of the links below: |
||||
|
||||
[[get-started:help]] |
||||
== Support |
||||
|
||||
There are a few support options available: |
||||
|
||||
[[get-started:help:community]] |
||||
=== Community Forum |
||||
|
||||
Spring Data on Stackoverflow http://stackoverflow.com/questions/tagged/spring-data[Stackoverflow ] is a tag for all Spring Data (not just Document) users to share information and help each other. Note that registration is needed *only* for posting. |
||||
|
||||
[[get-started:help:professional]] |
||||
=== Professional Support |
||||
|
||||
Professional, from-the-source support, with guaranteed response time, is available from http://gopivotal.com/[Pivotal Sofware, Inc.], the company behind Spring Data and Spring. |
||||
|
||||
[[get-started:up-to-date]] |
||||
== Following Development |
||||
|
||||
For information on the Spring Data Mongo source code repository, nightly builds and snapshot artifacts please see the http://projects.spring.io/spring-data-mongodb/[Spring Data Mongo homepage]. You can help make Spring Data best serve the needs of the Spring community by interacting with developers through the Community on http://stackoverflow.com/questions/tagged/spring-data[Stackoverflow]. To follow developer activity look for the mailing list information on the Spring Data Mongo homepage. If you encounter a bug or want to suggest an improvement, please create a ticket on the Spring Data issue https://jira.spring.io/browse/DATAMONGO[tracker]. To stay up to date with the latest news and announcements in the Spring eco system, subscribe to the Spring Community http://spring.io[Portal]. Lastly, you can follow the SpringSource Data http://spring.io/blog[blog ]or the project team on Twitter (http://twitter.com/SpringData[SpringData]). |
||||
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
[[introduction]] |
||||
= Introduction |
||||
|
||||
This document is the reference guide for Spring Data - Document Support. It explains Document module concepts and semantics and the syntax for various stores namespaces. |
||||
|
||||
This section provides some basic introduction to Spring and Document database. The rest of the document refers only to Spring Data Document features and assumes the user is familiar with document databases such as MongoDB and CouchDB as well as Spring concepts. |
||||
|
||||
[[get-started:first-steps:spring]] |
||||
== Knowing Spring |
||||
Spring Data uses Spring framework's http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/spring-core.html[core] functionality, such as the http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/beans.html[IoC] container, http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html#core-convert[type conversion system], http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/expressions.html[expression language], http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/jmx.html[JMX integration], and portable http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/dao.html#dao-exceptions[DAO exception hierarchy]. While it is not important to know the Spring APIs, understanding the concepts behind them is. At a minimum, the idea behind IoC should be familiar for whatever IoC container you choose to use. |
||||
|
||||
The core functionality of the MongoDB and CouchDB support can be used directly, with no need to invoke the IoC services of the Spring Container. This is much like `JdbcTemplate` which can be used 'standalone' without any other services of the Spring container. To leverage all the features of Spring Data document, such as the repository support, you will need to configure some parts of the library using Spring. |
||||
|
||||
To learn more about Spring, you can refer to the comprehensive (and sometimes disarming) documentation that explains in detail the Spring Framework. There are a lot of articles, blog entries and books on the matter - take a look at the Spring framework http://spring.io/docs[home page ] for more information. |
||||
|
||||
[[get-started:first-steps:nosql]] |
||||
== Knowing NoSQL and Document databases |
||||
NoSQL stores have taken the storage world by storm. It is a vast domain with a plethora of solutions, terms and patterns (to make things worth even the term itself has multiple http://www.google.com/search?q=nosoql+acronym[meanings]). While some of the principles are common, it is crucial that the user is familiar to some degree with the stores supported by DATADOC. The best way to get acquainted to this solutions is to read their documentation and follow their examples - it usually doesn't take more then 5-10 minutes to go through them and if you are coming from an RDMBS-only background many times these exercises can be an eye opener. |
||||
|
||||
The jumping off ground for learning about MongoDB is http://www.mongodb.org/[www.mongodb.org]. Here is a list of other useful resources: |
||||
|
||||
* The http://docs.mongodb.org/manual/[manual] introduces MongoDB and contains links to getting started guides, reference documentation and tutorials. |
||||
* The http://try.mongodb.org/[online shell] provides a convenient way to interact with a MongoDB instance in combination with the online http://docs.mongodb.org/manual/tutorial/getting-started/[tutorial.] |
||||
* MongoDB http://docs.mongodb.org/ecosystem/drivers/java/[Java Language Center] |
||||
* Several http://www.mongodb.org/books[books] available for purchase |
||||
* Karl Seguin's online book: http://openmymind.net/mongodb.pdf[The Little MongoDB Book] |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
[[requirements]] |
||||
= Requirements |
||||
|
||||
Spring Data MongoDB 1.x binaries requires JDK level 6.0 and above, and http://spring.io/docs[Spring Framework] 3.2.x and above. |
||||
|
||||
In terms of document stores, http://www.mongodb.org/[MongoDB] preferably version 2.4. |
||||
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
[[preface]] |
||||
[preface] |
||||
= Preface |
||||
|
||||
The Spring Data MongoDB project applies core Spring concepts to the development of solutions using the MongoDB document style data store. We provide a "template" as a high-level abstraction for storing and querying documents. You will notice similarities to the JDBC support in the Spring Framework. |
||||
@ -0,0 +1,243 @@
@@ -0,0 +1,243 @@
|
||||
[[mongo.cross.store]] |
||||
= Cross Store support |
||||
|
||||
Sometimes you need to store data in multiple data stores and these data stores can be of different types. One might be relational while the other a document store. For this use case we have created a separate module in the MongoDB support that handles what we call cross-store support. The current implementation is based on JPA as the driver for the relational database and we allow select fields in the Entities to be stored in a Mongo database. In addition to allowing you to store your data in two stores we also coordinate persistence operations for the non-transactional MongoDB store with the transaction life-cycle for the relational database. |
||||
|
||||
[[mongodb_cross-store-configuration]] |
||||
== Cross Store Configuration |
||||
|
||||
Assuming that you have a working JPA application and would like to add some cross-store persistence for MongoDB. What do you have to add to your configuration? |
||||
|
||||
First of all you need to add a dependency on the module. Using Maven this is done by adding a dependency to your pom: |
||||
|
||||
=== Example Maven pom.xml with spring-data-mongodb-cross-store dependency |
||||
|
||||
[source,xml] |
||||
---- |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
... |
||||
|
||||
<!-- Spring Data --> |
||||
<dependency> |
||||
<groupId>org.springframework.data</groupId> |
||||
<artifactId>spring-data-mongodb-cross-store</artifactId> |
||||
<version>${spring.data.mongo.version}</version> |
||||
</dependency> |
||||
|
||||
... |
||||
|
||||
</project> |
||||
---- |
||||
|
||||
Once this is done we need to enable AspectJ for the project. The cross-store support is implemented using AspectJ aspects so by enabling compile time AspectJ support the cross-store features will become available to your project. In Maven you would add an additional plugin to the <build> section of the pom: |
||||
|
||||
=== Example Maven pom.xml with AspectJ plugin enabled |
||||
|
||||
[source,xml] |
||||
---- |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
... |
||||
|
||||
<build> |
||||
<plugins> |
||||
|
||||
… |
||||
|
||||
<plugin> |
||||
<groupId>org.codehaus.mojo</groupId> |
||||
<artifactId>aspectj-maven-plugin</artifactId> |
||||
<version>1.0</version> |
||||
<dependencies> |
||||
<!-- NB: You must use Maven 2.0.9 or above or these are ignored (see MNG-2972) --> |
||||
<dependency> |
||||
<groupId>org.aspectj</groupId> |
||||
<artifactId>aspectjrt</artifactId> |
||||
<version>${aspectj.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.aspectj</groupId> |
||||
<artifactId>aspectjtools</artifactId> |
||||
<version>${aspectj.version}</version> |
||||
</dependency> |
||||
</dependencies> |
||||
<executions> |
||||
<execution> |
||||
<goals> |
||||
<goal>compile</goal> |
||||
<goal>test-compile</goal> |
||||
</goals> |
||||
</execution> |
||||
</executions> |
||||
<configuration> |
||||
<outxml>true</outxml> |
||||
<aspectLibraries> |
||||
<aspectLibrary> |
||||
<groupId>org.springframework</groupId> |
||||
<artifactId>spring-aspects</artifactId> |
||||
</aspectLibrary> |
||||
<aspectLibrary> |
||||
<groupId>org.springframework.data</groupId> |
||||
<artifactId>spring-data-mongodb-cross-store</artifactId> |
||||
</aspectLibrary> |
||||
</aspectLibraries> |
||||
<source>1.6</source> |
||||
<target>1.6</target> |
||||
</configuration> |
||||
</plugin> |
||||
|
||||
... |
||||
|
||||
</plugins> |
||||
</build> |
||||
|
||||
... |
||||
|
||||
</project> |
||||
---- |
||||
|
||||
Finally, you need to configure your project to use MongoDB and also configure the aspects that are used. The following XML snippet should be added to your application context: |
||||
|
||||
=== Example application context with MongoDB and cross-store aspect support |
||||
|
||||
[source,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:jdbc="http://www.springframework.org/schema/jdbc" |
||||
xmlns:jpa="http://www.springframework.org/schema/data/jpa" |
||||
xmlns:mongo="http://www.springframework.org/schema/data/mongo" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo |
||||
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd |
||||
http://www.springframework.org/schema/jdbc |
||||
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd |
||||
http://www.springframework.org/schema/beans |
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd |
||||
http://www.springframework.org/schema/data/jpa |
||||
http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd"> |
||||
|
||||
... |
||||
|
||||
<!-- Mongo config --> |
||||
<mongo:mongo host="localhost" port="27017"/> |
||||
|
||||
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> |
||||
<constructor-arg name="mongo" ref="mongo"/> |
||||
<constructor-arg name="databaseName" value="test"/> |
||||
<constructor-arg name="defaultCollectionName" value="cross-store"/> |
||||
</bean> |
||||
|
||||
<bean class="org.springframework.data.mongodb.core.MongoExceptionTranslator"/> |
||||
|
||||
<!-- Mongo cross-store aspect config --> |
||||
<bean class="org.springframework.data.persistence.document.mongo.MongoDocumentBacking" |
||||
factory-method="aspectOf"> |
||||
<property name="changeSetPersister" ref="mongoChangeSetPersister"/> |
||||
</bean> |
||||
<bean id="mongoChangeSetPersister" |
||||
class="org.springframework.data.persistence.document.mongo.MongoChangeSetPersister"> |
||||
<property name="mongoTemplate" ref="mongoTemplate"/> |
||||
<property name="entityManagerFactory" ref="entityManagerFactory"/> |
||||
</bean> |
||||
|
||||
... |
||||
|
||||
</beans> |
||||
---- |
||||
|
||||
[[mongodb_cross-store-application]] |
||||
== Writing the Cross Store Application |
||||
|
||||
We are assuming that you have a working JPA application so we will only cover the additional steps needed to persist part of your Entity in your Mongo database. First you need to identify the field you want persisted. It should be a domain class and follow the general rules for the Mongo mapping support covered in previous chapters. The field you want persisted in MongoDB should be annotated using the `@RelatedDocument` annotation. That is really all you need to do!. The cross-store aspects take care of the rest. This includes marking the field with `@Transient` so it won't be persisted using JPA, keeping track of any changes made to the field value and writing them to the database on successful transaction completion, loading the document from MongoDB the first time the value is used in your application. Here is an example of a simple Entity that has a field annotated with `@RelatedEntity`. |
||||
|
||||
=== Example of Entity with @RelatedDocument |
||||
|
||||
[source,java] |
||||
---- |
||||
@Entity |
||||
public class Customer { |
||||
|
||||
@Id |
||||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
||||
private Long id; |
||||
|
||||
private String firstName; |
||||
|
||||
private String lastName; |
||||
|
||||
@RelatedDocument |
||||
private SurveyInfo surveyInfo; |
||||
|
||||
// getters and setters omitted |
||||
} |
||||
---- |
||||
|
||||
=== Example of domain class to be stored as document |
||||
|
||||
[source,java] |
||||
---- |
||||
public class SurveyInfo { |
||||
|
||||
private Map<String, String> questionsAndAnswers; |
||||
|
||||
public SurveyInfo() { |
||||
this.questionsAndAnswers = new HashMap<String, String>(); |
||||
} |
||||
|
||||
public SurveyInfo(Map<String, String> questionsAndAnswers) { |
||||
this.questionsAndAnswers = questionsAndAnswers; |
||||
} |
||||
|
||||
public Map<String, String> getQuestionsAndAnswers() { |
||||
return questionsAndAnswers; |
||||
} |
||||
|
||||
public void setQuestionsAndAnswers(Map<String, String> questionsAndAnswers) { |
||||
this.questionsAndAnswers = questionsAndAnswers; |
||||
} |
||||
|
||||
public SurveyInfo addQuestionAndAnswer(String question, String answer) { |
||||
this.questionsAndAnswers.put(question, answer); |
||||
return this; |
||||
} |
||||
} |
||||
---- |
||||
|
||||
Once the SurveyInfo has been set on the Customer object above the MongoTemplate that was configured above is used to save the SurveyInfo along with some metadata about the JPA Entity is stored in a MongoDB collection named after the fully qualified name of the JPA Entity class. The following code: |
||||
|
||||
=== Example of code using the JPA Entity configured for cross-store persistence |
||||
|
||||
[source,java] |
||||
---- |
||||
Customer customer = new Customer(); |
||||
customer.setFirstName("Sven"); |
||||
customer.setLastName("Olafsen"); |
||||
SurveyInfo surveyInfo = new SurveyInfo() |
||||
.addQuestionAndAnswer("age", "22") |
||||
.addQuestionAndAnswer("married", "Yes") |
||||
.addQuestionAndAnswer("citizenship", "Norwegian"); |
||||
customer.setSurveyInfo(surveyInfo); |
||||
customerRepository.save(customer); |
||||
---- |
||||
|
||||
Executing the code above results in the following JSON document stored in MongoDB. |
||||
|
||||
=== Example of JSON document stored in MongoDB |
||||
|
||||
[source,javascript] |
||||
---- |
||||
{ "_id" : ObjectId( "4d9e8b6e3c55287f87d4b79e" ), |
||||
"_entity_id" : 1, |
||||
"_entity_class" : "org.springframework.data.mongodb.examples.custsvc.domain.Customer", |
||||
"_entity_field_name" : "surveyInfo", |
||||
"questionsAndAnswers" : { "married" : "Yes", |
||||
"age" : "22", |
||||
"citizenship" : "Norwegian" }, |
||||
"_entity_field_class" : "org.springframework.data.mongodb.examples.custsvc.domain.SurveyInfo" } |
||||
---- |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
[[introduction]] |
||||
= Introduction |
||||
|
||||
== Document Structure |
||||
|
||||
This part of the reference documentation explains the core functionality offered by Spring Data Document. |
||||
|
||||
<<mongo.core>> introduces the MongoDB module feature set. |
||||
|
||||
<<mongo.repositories>> introduces the repository support for MongoDB. |
||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
[[mongo.jmx]] |
||||
= JMX support |
||||
|
||||
The JMX support for MongoDB exposes the results of executing the 'serverStatus' command on the admin database for a single MongoDB server instance. It also exposes an administrative MBean, MongoAdmin which will let you perform administrative operations such as drop or create a database. The JMX features build upon the JMX feature set available in the Spring Framework. See http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/jmx.html[here ] for more details. |
||||
|
||||
[[mongodb:jmx-configuration]] |
||||
== MongoDB JMX Configuration |
||||
|
||||
Spring's Mongo namespace enables you to easily enable JMX functionality |
||||
|
||||
=== XML schema to configure MongoDB |
||||
|
||||
[source,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 |
||||
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"/> |
||||
|
||||
<!-- by default look for a Mongo object named 'mongo' --> |
||||
<mongo:jmx/> |
||||
|
||||
<context:mbean-export/> |
||||
|
||||
<!-- To translate any MongoExceptions thrown in @Repository annotated classes --> |
||||
<context:annotation-config/> |
||||
|
||||
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean" p:port="1099" /> |
||||
|
||||
<!-- Expose JMX over RMI --> |
||||
<bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" |
||||
depends-on="registry" |
||||
p:objectName="connector:name=rmi" |
||||
p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/myconnector" /> |
||||
|
||||
</beans> |
||||
---- |
||||
|
||||
This will expose several MBeans |
||||
|
||||
* AssertMetrics |
||||
* BackgroundFlushingMetrics |
||||
* BtreeIndexCounters |
||||
* ConnectionMetrics |
||||
* GlobalLoclMetrics |
||||
* MemoryMetrics |
||||
* OperationCounters |
||||
* ServerInfo |
||||
* MongoAdmin |
||||
|
||||
This is shown below in a screenshot from JConsole |
||||
|
||||
image::jconsole.png[] |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
[[mongo.logging]] |
||||
= Logging support |
||||
|
||||
An appender for Log4j is provided in the maven module "spring-data-mongodb-log4j". Note, there is no dependency on other Spring Mongo modules, only the MongoDB driver. |
||||
|
||||
[[mongodb:logging-configuration]] |
||||
== MongoDB Log4j Configuration |
||||
|
||||
Here is an example configuration |
||||
|
||||
[source] |
||||
---- |
||||
log4j.rootCategory=INFO, stdout |
||||
|
||||
log4j.appender.stdout=org.springframework.data.document.mongodb.log4j.MongoLog4jAppender |
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout |
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n |
||||
log4j.appender.stdout.host = localhost |
||||
log4j.appender.stdout.port = 27017 |
||||
log4j.appender.stdout.database = logs |
||||
log4j.appender.stdout.collectionPattern = %X{year}%X{month} |
||||
log4j.appender.stdout.applicationId = my.application |
||||
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE |
||||
|
||||
log4j.category.org.apache.activemq=ERROR |
||||
log4j.category.org.springframework.batch=DEBUG |
||||
log4j.category.org.springframework.data.document.mongodb=DEBUG |
||||
log4j.category.org.springframework.transaction=INFO |
||||
---- |
||||
|
||||
The important configuration to look at aside from host and port is the database and collectionPattern. The variables year, month, day and hour are available for you to use in forming a collection name. This is to support the common convention of grouping log information in a collection that corresponds to a specific time period, for example a collection per day. |
||||
|
||||
There is also an applicationId which is put into the stored message. The document stored from logging as the following keys: level, name, applicationId, timestamp, properties, traceback, and message. |
||||
@ -0,0 +1,425 @@
@@ -0,0 +1,425 @@
|
||||
[[mapping-chapter]] |
||||
= Mapping |
||||
|
||||
Rich mapping support is provided by the `MongoMappingConverter`. `MongoMappingConverter` has a rich metadata model that provides a full feature set of functionality to map domain objects to MongoDB documents.The mapping metadata model is populated using annotations on your domain objects. However, the infrastructure is not limited to using annotations as the only source of metadata information. The `MongoMappingConverter` also allows you to map objects to documents without providing any additional metadata, by following a set of conventions. |
||||
|
||||
In this section we will describe the features of the `MongoMappingConverter`. How to use conventions for mapping objects to documents and how to override those conventions with annotation based mapping metadata. |
||||
|
||||
NOTE: `SimpleMongoConverter` has been deprecated in Spring Data MongoDB M3 as all of its functionality has been subsumed into `MappingMongoConverter`. |
||||
|
||||
[[mapping-conventions]] |
||||
== Convention based Mapping |
||||
|
||||
`MongoMappingConverter` has a few conventions for mapping objects to documents when no additional mapping metadata is provided. The conventions are: |
||||
|
||||
* The short Java class name is mapped to the collection name in the following manner. The class '`com.bigbank.SavingsAccount`' maps to '`savingsAccount`' collection name. |
||||
* All nested objects are stored as nested objects in the document and *not* as DBRefs |
||||
* The converter will use any Spring Converters registered with it to override the default mapping of object properties to document field/values. |
||||
* The fields of an object are used to convert to and from fields in the document. Public JavaBean properties are not used. |
||||
* You can have a single non-zero argument constructor whose constructor argument names match top level field names of document, that constructor will be used. Otherwise the zero arg constructor will be used. if there is more than one non-zero argument constructor an exception will be thrown. |
||||
|
||||
[[mapping.conventions.id-field]] |
||||
=== How the '_id' field is handled in the mapping layer |
||||
|
||||
MongoDB 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. The "_id" field can be of any type the, other than arrays, so long as it is unique. The driver naturally supports all primitive types and Dates. 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 field will be mapped to the '_id' document field: |
||||
|
||||
* A field annotated with `@Id` (`org.springframework.data.annotation.Id`) will be mapped to the '_id' field. |
||||
* A field without an annotation but named `id` will be mapped to the '_id' field. |
||||
|
||||
The following outlines what type conversion, if any, will be done on the property mapped to the _id document field. |
||||
|
||||
* If a field named 'id' is declared as a String or BigInteger in the Java class it will be converted to and stored as an ObjectId if possible. ObjectId as a field type is also valid. If you specify a value for 'id' in your application, the conversion to an ObjectId is detected to the MongoDBdriver. If the specified 'id' value cannot be converted to an ObjectId, then the value will be stored as is in the document's _id field. |
||||
* If a field named ' id' id field is not declared as a String, BigInteger, or ObjectID in the Java class then you should assign it a value in your application so it can be stored 'as-is' in the document's _id field. |
||||
* If no field named 'id' 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 `MongoTemplate` 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. |
||||
|
||||
[[mapping-configuration]] |
||||
== Mapping Configuration |
||||
|
||||
Unless explicitly configured, an instance of `MongoMappingConverter` is created by default when creating a `MongoTemplate`. You can create your own instance of the `MappingMongoConverter` so as to tell it where to scan the classpath at startup your domain classes in order to extract metadata and construct indexes. Also, by creating your own instance you can register Spring converters to use for mapping specific classes to and from the database. |
||||
|
||||
You can configure the `MongoMappingConverter` as well as `com.mongodb.Mongo` and MongoTemplate either using Java or XML based metadata. Here is an example using Spring's Java based configuration |
||||
|
||||
=== @Configuration class to configure MongoDB mapping support |
||||
|
||||
[source,java] |
||||
---- |
||||
@Configuration |
||||
public class GeoSpatialAppConfig extends AbstractMongoConfiguration { |
||||
|
||||
@Bean |
||||
public Mongo mongo() throws Exception { |
||||
return new Mongo("localhost"); |
||||
} |
||||
|
||||
@Override |
||||
public String getDatabaseName() { |
||||
return "database"; |
||||
} |
||||
|
||||
@Override |
||||
public String getMappingBasePackage() { |
||||
return "com.bigbank.domain"; |
||||
} |
||||
|
||||
// the following are optional |
||||
|
||||
|
||||
@Bean |
||||
@Override |
||||
public CustomConversions customConversions() throws Exception { |
||||
List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>(); |
||||
converterList.add(new org.springframework.data.mongodb.test.PersonReadConverter()); |
||||
converterList.add(new org.springframework.data.mongodb.test.PersonWriteConverter()); |
||||
return new CustomConversions(converterList); |
||||
} |
||||
|
||||
@Bean |
||||
public LoggingEventListener<MongoMappingEvent> mappingEventsListener() { |
||||
return new LoggingEventListener<MongoMappingEvent>(); |
||||
} |
||||
} |
||||
---- |
||||
|
||||
`AbstractMongoConfiguration` requires you to implement methods that define a `com.mongodb.Mongo` as well as provide a database name. `AbstractMongoConfiguration` also has a method you can override named '`getMappingBasePackage`' which tells the converter where to scan for classes annotated with the `@org.springframework.data.mongodb.core.mapping.Document` annotation. |
||||
|
||||
You can add additional converters to the converter by overriding the method afterMappingMongoConverterCreation. Also shown in the above example is a `LoggingEventListener` which logs `MongoMappingEvent`s that are posted onto Spring's `ApplicationContextEvent` infrastructure. |
||||
|
||||
NOTE: AbstractMongoConfiguration will create a MongoTemplate instance and registered with the container under the name 'mongoTemplate'. |
||||
|
||||
You can also override the method `UserCredentials getUserCredentials()` to provide the username and password information to connect to the database. |
||||
|
||||
Spring's MongoDB namespace enables you to easily enable mapping functionality in XML |
||||
|
||||
=== XML schema to configure MongoDB mapping support |
||||
|
||||
[source,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 |
||||
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"/> |
||||
|
||||
<mongo:db-factory dbname="database" mongo-ref="mongo"/> |
||||
|
||||
<!-- by default look for a Mongo object named 'mongo' - default name used for the converter is 'mappingConverter' --> |
||||
<mongo:mapping-converter base-package="com.bigbank.domain"> |
||||
<mongo:custom-converters> |
||||
<mongo:converter ref="readConverter"/> |
||||
<mongo:converter> |
||||
<bean class="org.springframework.data.mongodb.test.PersonWriteConverter"/> |
||||
</mongo:converter> |
||||
</mongo:custom-converters> |
||||
</mongo:mapping-converter> |
||||
|
||||
<bean id="readConverter" class="org.springframework.data.mongodb.test.PersonReadConverter"/> |
||||
|
||||
<!-- set the mapping converter to be used by the MongoTemplate --> |
||||
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> |
||||
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> |
||||
<constructor-arg name="mongoConverter" ref="mappingConverter"/> |
||||
</bean> |
||||
|
||||
<bean class="org.springframework.data.mongodb.core.mapping.event.LoggingEventListener"/> |
||||
|
||||
</beans> |
||||
---- |
||||
|
||||
The `base-package` property tells it where to scan for classes annotated with the `@org.springframework.data.mongodb.core.mapping.Document` annotation. |
||||
|
||||
[[mapping-usage]] |
||||
== Metadata based Mapping |
||||
|
||||
To take full advantage of the object mapping functionality inside the Spring Data/MongoDB support, you should annotate your mapped objects with the `@org.springframework.data.mongodb.core.mapping.Document` annotation. Although it is not necessary for the mapping framework to have this annotation (your POJOs will be mapped correctly, even without any annotations), it allows the classpath scanner to find and pre-process your domain objects to extract the necessary metadata. If you don't use this annotation, your application will take a slight performance hit the first time you store a domain object because the mapping framework needs to build up its internal metadata model so it knows about the properties of your domain object and how to persist them. |
||||
|
||||
=== Example domain object |
||||
|
||||
[source,java] |
||||
---- |
||||
package com.mycompany.domain; |
||||
|
||||
@Document |
||||
public class Person { |
||||
|
||||
@Id |
||||
private ObjectId id; |
||||
|
||||
@Indexed |
||||
private Integer ssn; |
||||
|
||||
private String firstName; |
||||
|
||||
@Indexed |
||||
private String lastName; |
||||
} |
||||
---- |
||||
|
||||
The `@Id` annotation tells the mapper which property you want to use for the MongoDB `_id` property and the `@Indexed` annotation tells the mapping framework to call `ensureIndex` on that property of your document, making searches faster. |
||||
|
||||
Automatic index creation is only done for types annotated with `@Document`. |
||||
|
||||
[[mapping-usage-annotations]] |
||||
=== Mapping annotation overview |
||||
|
||||
The MappingMongoConverter can use metadata to drive the mapping of objects to documents. An overview of the annotations is provided below |
||||
|
||||
* `@Id `- applied at the field level to mark the field used for identiy purpose. |
||||
* `@Document` - applied at the class level to indicate this class is a candidate for mapping to the database. You can specify the name of the collection where the database will be stored. |
||||
* `@DBRef` - applied at the field to indicate it is to be stored using a com.mongodb.DBRef. |
||||
* `@Indexed` - applied at the field level to describe how to index the field. |
||||
* `@CompoundIndex` - applied at the type level to declare Compound Indexes |
||||
* `@GeoSpatialIndexed` - applied at the field level to describe how to geoindex the field. |
||||
* `@TextIndexed` - applied at the field level to mark the field to be included in the text index. |
||||
* `@Language` - applied at the field level to set the language override property for text index. |
||||
* `@Transient` - by default all private fields are mapped to the document, this annotation excludes the field where it is applied from being stored in the database |
||||
* `@PersistenceConstructor` - marks a given constructor - even a package protected one - to use when instantiating the object from the database. Constructor arguments are mapped by name to the key values in the retrieved DBObject. |
||||
* `@Value` - this annotation is part of the Spring Framework . Within the mapping framework it can be applied to constructor arguments. This lets you use a Spring Expression Language statement to transform a key's value retrieved in the database before it is used to construct a domain object. In order to reference a property of a given document one has to use expressions like: `@Value("#root.myProperty")` where `root` refers to the root of the given document. |
||||
* `@Field` - applied at the field level and described the name of the field as it will be represented in the MongoDB BSON document thus allowing the name to be different than the fieldname of the class. |
||||
|
||||
The mapping metadata infrastructure is defined in a seperate spring-data-commons project that is technology agnostic. Specific subclasses are using in the MongoDB support to support annotation based metadata. Other strategies are also possible to put in place if there is demand. |
||||
|
||||
Here is an example of a more complex mapping. |
||||
|
||||
[source,java] |
||||
---- |
||||
@Document |
||||
@CompoundIndexes({ |
||||
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}") |
||||
}) |
||||
public class Person<T extends Address> { |
||||
|
||||
@Id |
||||
private String id; |
||||
|
||||
@Indexed(unique = true) |
||||
private Integer ssn; |
||||
|
||||
@Field("fName") |
||||
private String firstName; |
||||
|
||||
@Indexed |
||||
private String lastName; |
||||
|
||||
private Integer age; |
||||
|
||||
@Transient |
||||
private Integer accountTotal; |
||||
|
||||
@DBRef |
||||
private List<Account> accounts; |
||||
|
||||
private T address; |
||||
|
||||
|
||||
public Person(Integer ssn) { |
||||
this.ssn = ssn; |
||||
} |
||||
|
||||
@PersistenceConstructor |
||||
public Person(Integer ssn, String firstName, String lastName, Integer age, T address) { |
||||
this.ssn = ssn; |
||||
this.firstName = firstName; |
||||
this.lastName = lastName; |
||||
this.age = age; |
||||
this.address = address; |
||||
} |
||||
|
||||
public String getId() { |
||||
return id; |
||||
} |
||||
|
||||
// no setter for Id. (getter is only exposed for some unit testing) |
||||
|
||||
public Integer getSsn() { |
||||
return ssn; |
||||
} |
||||
|
||||
// other getters/setters ommitted |
||||
---- |
||||
|
||||
[[mapping-custom-object-construction]] |
||||
=== Customized Object Construction |
||||
|
||||
The mapping subsystem allows the customization of the object construction by annotating a constructor with the `@PersistenceConstructor` annotation. The values to be used for the constructor parameters are resolved in the following way: |
||||
|
||||
* If a parameter is annotated with the `@Value` annotation, the given expression is evaluated and the result is used as the parameter value. |
||||
* If the Java type has a property whose name matches the given field of the input document, then it's property information is used to select the appropriate constructor parameter to pass the input field value to. This works only if the parameter name information is present in the java `.class` files which can be achieved by compiling the source with debug information or using the new `-parameters` command-line switch for javac in Java 8. |
||||
* Otherwise an `MappingException` will be thrown indicating that the given constructor parameter could not be bound. |
||||
|
||||
[source,java] |
||||
---- |
||||
class OrderItem { |
||||
|
||||
private @Id String id; |
||||
private int quantity; |
||||
private double unitPrice; |
||||
|
||||
OrderItem(String id, @Value("#root.qty ?: 0") int quantity, double unitPrice) { |
||||
this.id = id; |
||||
this.quantity = quantity; |
||||
this.unitPrice = unitPrice; |
||||
} |
||||
|
||||
// getters/setters ommitted |
||||
} |
||||
|
||||
DBObject input = new BasicDBObject("id", "4711"); |
||||
input.put("unitPrice", 2.5); |
||||
input.put("qty",5); |
||||
OrderItem item = converter.read(OrderItem.class, input); |
||||
---- |
||||
|
||||
NOTE: The SpEL expression in the `@Value` annotation of the `quantity` parameter falls back to the value `0` if the given property path cannot be resolved. |
||||
|
||||
Additional examples for using the `@PersistenceConstructor` annotation can be found in the https://github.com/spring-projects/spring-data-mongodb/blob/master/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java[MappingMongoConverterUnitTests] test suite. |
||||
|
||||
[[mapping-usage-indexes.compound-index]] |
||||
=== Compound Indexes |
||||
|
||||
Compound indexes are also supported. They are defined at the class level, rather than on indidividual properties. |
||||
|
||||
NOTE: Compound indexes are very important to improve the performance of queries that involve criteria on multiple fields |
||||
|
||||
Here's an example that creates a compound index of `lastName` in ascending order and `age` in descending order: |
||||
|
||||
==== Example Compound Index Usage |
||||
|
||||
[source,java] |
||||
---- |
||||
package com.mycompany.domain; |
||||
|
||||
@Document |
||||
@CompoundIndexes({ |
||||
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}") |
||||
}) |
||||
public class Person { |
||||
|
||||
@Id |
||||
private ObjectId id; |
||||
private Integer age; |
||||
private String firstName; |
||||
private String lastName; |
||||
|
||||
} |
||||
---- |
||||
|
||||
[[mapping-usage-indexes.text-index]] |
||||
=== Text Indexes |
||||
|
||||
NOTE: The text index feature is disabled by default for mongodb v.2.4. |
||||
|
||||
Creating a text index allows to accumulate several fields into a searchable full text index. It is only possible to have one text index per collection so all fields marked with `@TextIndexed` are combined into this index. Properties can be weighted to influence document score for ranking results. The default language for the text index is english, to change the default language set `@Document(language="spanish")` to any language you want. Using a property called `language` or `@Language` allows to define a language override on a per document base. |
||||
|
||||
==== Example Text Index Usage |
||||
|
||||
[source,java] |
||||
---- |
||||
@Document(language = "spanish") |
||||
class SomeEntity { |
||||
|
||||
@TextIndexed String foo; |
||||
|
||||
@Language String lang; |
||||
|
||||
Nested nested; |
||||
} |
||||
|
||||
class Nested { |
||||
|
||||
@TextIndexed(weight=5) String bar; |
||||
String roo; |
||||
} |
||||
---- |
||||
|
||||
[[mapping-usage-references]] |
||||
=== Using DBRefs |
||||
|
||||
The mapping framework doesn't have to store child objects embedded within the document. You can also store them separately and use a DBRef to refer to that document. When the object is loaded from MongoDB, those references will be eagerly resolved and you will get back a mapped object that looks the same as if it had been stored embedded within your master document. |
||||
|
||||
Here's an example of using a DBRef to refer to a specific document that exists independently of the object in which it is referenced (both classes are shown in-line for brevity's sake): |
||||
|
||||
[source,java] |
||||
---- |
||||
@Document |
||||
public class Account { |
||||
|
||||
@Id |
||||
private ObjectId id; |
||||
private Float total; |
||||
} |
||||
|
||||
@Document |
||||
public class Person { |
||||
|
||||
@Id |
||||
private ObjectId id; |
||||
@Indexed |
||||
private Integer ssn; |
||||
@DBRef |
||||
private List<Account> accounts; |
||||
} |
||||
---- |
||||
|
||||
There's no need to use something like `@OneToMany` because the mapping framework sees that you're wanting a one-to-many relationship because there is a List of objects. When the object is stored in MongoDB, there will be a list of DBRefs rather than the `Account` objects themselves. |
||||
|
||||
The mapping framework does not handle cascading saves. If you change an `Account` object that is referenced by a `Person` object, you must save the Account object separately. Calling `save` on the `Person` object will not automatically save the `Account` objects in the property `accounts`. |
||||
|
||||
[[mapping-usage-events]] |
||||
=== Mapping Framework Events |
||||
|
||||
Events are fired throughout the lifecycle of the mapping process. This is described in the <<mongodb.mapping-usage.events,Lifecycle Events>> section. |
||||
|
||||
Simply declaring these beans in your Spring ApplicationContext will cause them to be invoked whenever the event is dispatched. |
||||
|
||||
[[mapping-explicit-converters]] |
||||
=== Overriding Mapping with explicit Converters |
||||
|
||||
When storing and querying your objects it is convenient to have a `MongoConverter` instance handle the mapping of all Java types to DBObjects. However, sometimes you may want the `MongoConverter`'s do most of the work but allow you to selectively handle the conversion for a particular type or to optimize performance. |
||||
|
||||
To selectively handle the conversion yourself, register one or more one or more `org.springframework.core.convert.converter.Converter` instances with the MongoConverter. |
||||
|
||||
NOTE: Spring 3.0 introduced a core.convert package that provides a general type conversion system. This is described in detail in the Spring reference documentation section entitled http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html#core-convert[Spring 3 Type Conversion]. |
||||
|
||||
The method `customConversions` in `AbstractMongoConfiguration` can be used to configure Converters. The examples <<mapping-configuration,here>> at the beginning of this chapter show how to perform the configuration using Java and XML. |
||||
|
||||
Below is an example of a Spring Converter implementation that converts from a DBObject to a Person POJO. |
||||
|
||||
[source,java] |
||||
---- |
||||
@ReadingConverter |
||||
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; |
||||
} |
||||
} |
||||
---- |
||||
|
||||
Here is an example that converts from a Person to a DBObject. |
||||
|
||||
[source,java] |
||||
---- |
||||
@WritingConverter |
||||
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; |
||||
} |
||||
} |
||||
---- |
||||
@ -0,0 +1,334 @@
@@ -0,0 +1,334 @@
|
||||
[[mongo.repositories]] |
||||
= MongoDB repositories |
||||
|
||||
[[mongo-repo-intro]] |
||||
== Introduction |
||||
|
||||
This chapter will point out the specialties for repository support for MongoDB. This builds on the core repository support explained in <<repositories>>. So make sure you've got a sound understanding of the basic concepts explained there. |
||||
|
||||
[[mongo-repo-usage]] |
||||
== Usage |
||||
|
||||
To access domain entities stored in a MongoDB you can leverage our sophisticated repository support that eases implementing those quite significantly. To do so, simply create an interface for your repository: |
||||
|
||||
=== Sample Person entity |
||||
|
||||
[source,java] |
||||
---- |
||||
public class Person { |
||||
|
||||
@Id |
||||
private String id; |
||||
private String firstname; |
||||
private String lastname; |
||||
private Address address; |
||||
|
||||
// … getters and setters omitted |
||||
} |
||||
---- |
||||
|
||||
We have a quite simple domain object here. Note that it has a property named `id` of type`ObjectId`. The default serialization mechanism used in `MongoTemplate` (which is backing the repository support) regards properties named id as document id. Currently we support`String`, `ObjectId` and `BigInteger` as id-types. |
||||
|
||||
=== Basic repository interface to persist Person entities |
||||
|
||||
[source] |
||||
---- |
||||
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> { |
||||
|
||||
// additional custom finder methods go here |
||||
} |
||||
---- |
||||
|
||||
Right now this interface simply serves typing purposes but we will add additional methods to it later. In your Spring configuration simply add |
||||
|
||||
=== General MongoDB repository Spring configuration |
||||
|
||||
[source,xml] |
||||
---- |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<beans xmlns="http://www.springframework.org/schema/beans" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns:mongo="http://www.springframework.org/schema/data/mongo" |
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans |
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd |
||||
http://www.springframework.org/schema/data/mongo |
||||
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"> |
||||
|
||||
<mongo:mongo id="mongo" /> |
||||
|
||||
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> |
||||
<constructor-arg ref="mongo" /> |
||||
<constructor-arg value="databaseName" /> |
||||
</bean> |
||||
|
||||
<mongo:repositories base-package="com.acme.*.repositories" /> |
||||
|
||||
</beans> |
||||
---- |
||||
|
||||
This namespace element will cause the base packages to be scanned for interfaces extending `MongoRepository` and create Spring beans for each of them found. By default the repositories will get a `MongoTemplate` Spring bean wired that is called `mongoTemplate`, so you only need to configure `mongo-template-ref` explicitly if you deviate from this convention. |
||||
|
||||
If you'd rather like to go with JavaConfig use the `@EnableMongoRepositories` annotation. The annotation carries the very same attributes like the namespace element. If no base package is configured the infrastructure will scan the package of the annotated configuration class. |
||||
|
||||
=== JavaConfig for repositories |
||||
|
||||
[source,java] |
||||
---- |
||||
@Configuration |
||||
@EnableMongoRepositories |
||||
class ApplicationConfig extends AbstractMongoConfiguration { |
||||
|
||||
@Override |
||||
protected String getDatabaseName() { |
||||
return "e-store"; |
||||
} |
||||
|
||||
@Override |
||||
public Mongo mongo() throws Exception { |
||||
return new Mongo(); |
||||
} |
||||
|
||||
@Override |
||||
protected String getMappingBasePackage() { |
||||
return "com.oreilly.springdata.mongodb" |
||||
} |
||||
} |
||||
---- |
||||
|
||||
As our domain repository extends `PagingAndSortingRepository` it provides you with CRUD operations as well as methods for paginated and sorted access to the entities. Working with the repository instance is just a matter of dependency injecting it into a client. So accessing the second page of `Person`s at a page size of 10 would simply look something like this: |
||||
|
||||
=== Paging access to Person entities |
||||
|
||||
[source,java] |
||||
---- |
||||
@RunWith(SpringJUnit4ClassRunner.class) |
||||
@ContextConfiguration |
||||
public class PersonRepositoryTests { |
||||
|
||||
@Autowired PersonRepository repository; |
||||
|
||||
@Test |
||||
public void readsFirstPageCorrectly() { |
||||
|
||||
Page<Person> persons = repository.findAll(new PageRequest(0, 10)); |
||||
assertThat(persons.isFirstPage(), is(true)); |
||||
} |
||||
} |
||||
---- |
||||
|
||||
The sample creates an application context with Spring's unit test support which will perform annotation based dependency injection into test cases. Inside the test method we simply use the repository to query the datastore. We hand the repository a `PageRequest` instance that requests the first page of persons at a page size of 10. |
||||
|
||||
[[mongodb.repositories.queries]] |
||||
== Query methods |
||||
|
||||
Most of the data access operations you usually trigger on a repository result a query being executed against the MongoDB databases. Defining such a query is just a matter of declaring a method on the repository interface |
||||
|
||||
=== PersonRepository with query methods |
||||
|
||||
[source,java] |
||||
---- |
||||
public interface PersonRepository extends PagingAndSortingRepository<Person, String> { |
||||
|
||||
List<Person> findByLastname(String lastname); |
||||
|
||||
Page<Person> findByFirstname(String firstname, Pageable pageable); |
||||
|
||||
Person findByShippingAddresses(Address address); |
||||
} |
||||
---- |
||||
|
||||
The first method shows a query for all people with the given lastname. The query will be derived parsing the method name for constraints which can be concatenated with `And` and `Or`. Thus the method name will result in a query expression of`{"lastname" : lastname}`. The second example shows how pagination is applied to a query. Just equip your method signature with a `Pageable` parameter and let the method return a `Page` instance and we will automatically page the query accordingly. The third examples shows that you can query based on properties which are not a primitive type. |
||||
|
||||
NOTE: Note that for version 1.0 we currently don't support referring to parameters that are mapped as `DBRef` in the domain class. |
||||
|
||||
[[mongodb.repositories.queries.delete]] |
||||
=== Repository delete queries |
||||
|
||||
The above keywords can be used in conjunciton with `delete…By` or `remove…By` to create queries deleting matching documents. |
||||
|
||||
==== `Delete…By` Query |
||||
|
||||
[source,java] |
||||
---- |
||||
public interface PersonRepository extends MongoRepository<Person, String> { |
||||
|
||||
List <Person> deleteByLastname(String lastname); |
||||
|
||||
Long deletePersonByLastname(String lastname); |
||||
} |
||||
---- |
||||
|
||||
Using return type `List` will retrieve and return all matching documents before actually deleting them. A numeric return type directly removes the matching documents returning the total number of documents removed. |
||||
|
||||
[[mongodb.repositories.queries.geo-spatial]] |
||||
=== Geo-spatial repository queries |
||||
|
||||
As you've just seen there are a few keywords triggering geo-spatial operations within a MongoDB query. The `Near` keyword allows some further modification. Let's have look at some examples: |
||||
|
||||
==== Advanced `Near` queries |
||||
|
||||
[source,java] |
||||
---- |
||||
public interface PersonRepository extends MongoRepository<Person, String> |
||||
|
||||
// { 'location' : { '$near' : [point.x, point.y], '$maxDistance' : distance}} |
||||
List<Person> findByLocationNear(Point location, Distance distance); |
||||
} |
||||
---- |
||||
|
||||
Adding a `Distance` parameter to the query method allows restricting results to those within the given distance. If the `Distance` was set up containing a `Metric` we will transparently use `$nearSphere` instead of $code. |
||||
|
||||
==== Using `Distance` with `Metrics` |
||||
|
||||
[source,java] |
||||
---- |
||||
Point point = new Point(43.7, 48.8); |
||||
Distance distance = new Distance(200, Metrics.KILOMETERS); |
||||
… = repository.findByLocationNear(point, distance); |
||||
// {'location' : {'$nearSphere' : [43.7, 48.8], '$maxDistance' : 0.03135711885774796}} |
||||
---- |
||||
|
||||
As you can see using a `Distance` equipped with a `Metric` causes `$nearSphere` clause to be added instead of a plain `$near`. Beyond that the actual distance gets calculated according to the `Metrics` used. |
||||
|
||||
==== Geo-near queries |
||||
|
||||
[source,java] |
||||
---- |
||||
public interface PersonRepository extends MongoRepository<Person, String> |
||||
|
||||
// {'geoNear' : 'location', 'near' : [x, y] } |
||||
GeoResults<Person> findByLocationNear(Point location); |
||||
|
||||
// No metric: {'geoNear' : 'person', 'near' : [x, y], maxDistance : distance } |
||||
// Metric: {'geoNear' : 'person', 'near' : [x, y], 'maxDistance' : distance, |
||||
// 'distanceMultiplier' : metric.multiplier, 'spherical' : true } |
||||
GeoResults<Person> findByLocationNear(Point location, Distance distance); |
||||
|
||||
// {'geoNear' : 'location', 'near' : [x, y] } |
||||
GeoResults<Person> findByLocationNear(Point location); |
||||
} |
||||
---- |
||||
|
||||
[[mongodb.repositories.queries.json-based]] |
||||
=== MongoDB JSON based query methods and field restriction |
||||
|
||||
By adding the annotation `org.springframework.data.mongodb.repository.Query` repository finder methods you can specify a MongoDB JSON query string to use instead of having the query derived from the method name. For example |
||||
|
||||
[source,java] |
||||
---- |
||||
public interface PersonRepository extends MongoRepository<Person, String> |
||||
|
||||
@Query("{ 'firstname' : ?0 }") |
||||
List<Person> findByThePersonsFirstname(String firstname); |
||||
|
||||
} |
||||
---- |
||||
|
||||
The placeholder ?0 lets you substitute the value from the method arguments into the JSON query string. |
||||
|
||||
You can also use the filter property to restrict the set of properties that will be mapped into the Java object. For example, |
||||
|
||||
[source,java] |
||||
---- |
||||
public interface PersonRepository extends MongoRepository<Person, String> |
||||
|
||||
@Query(value="{ 'firstname' : ?0 }", fields="{ 'firstname' : 1, 'lastname' : 1}") |
||||
List<Person> findByThePersonsFirstname(String firstname); |
||||
|
||||
} |
||||
---- |
||||
|
||||
This will return only the firstname, lastname and Id properties of the Person objects. The age property, a java.lang.Integer, will not be set and its value will therefore be null. |
||||
|
||||
[[mongodb.repositories.queries.type-safe]] |
||||
=== Type-safe Query methods |
||||
|
||||
MongoDB repository support integrates with the http://www.querydsl.com/[QueryDSL] project which provides a means to perform type-safe queries in Java. To quote from the project description, "Instead of writing queries as inline strings or externalizing them into XML files they are constructed via a fluent API." It provides the following features |
||||
|
||||
* Code completion in IDE (all properties, methods and operations can be expanded in your favorite Java IDE) |
||||
* Almost no syntactically invalid queries allowed (type-safe on all levels) |
||||
* Domain types and properties can be referenced safely (no Strings involved!) |
||||
* Adopts better to refactoring changes in domain types |
||||
* Incremental query definition is easier |
||||
|
||||
Please refer to the QueryDSL documentation which describes how to bootstrap your environment for APT based code generation http://source.mysema.com/static/querydsl/2.1.2/reference/html/ch02.html#d0e112[using Maven] or http://source.mysema.com/static/querydsl/2.1.2/reference/html/ch02.html#d0e131[using Ant]. |
||||
|
||||
Using QueryDSL you will be able to write queries as shown below |
||||
|
||||
[source,java] |
||||
---- |
||||
QPerson person = new QPerson("person"); |
||||
List<Person> result = repository.findAll(person.address.zipCode.eq("C0123")); |
||||
|
||||
Page<Person> page = repository.findAll(person.lastname.contains("a"), |
||||
new PageRequest(0, 2, Direction.ASC, "lastname")); |
||||
---- |
||||
|
||||
`QPerson` is a class that is generated (via the Java annotation post processing tool) which is a `Predicate` that allows you to write type safe queries. Notice that there are no strings in the query other than the value "C0123". |
||||
|
||||
You can use the generated `Predicate` class via the interface `QueryDslPredicateExecutor` which is shown below |
||||
|
||||
[source,java] |
||||
---- |
||||
public interface QueryDslPredicateExecutor<T> { |
||||
|
||||
T findOne(Predicate predicate); |
||||
|
||||
List<T> findAll(Predicate predicate); |
||||
|
||||
List<T> findAll(Predicate predicate, OrderSpecifier<?>... orders); |
||||
|
||||
Page<T> findAll(Predicate predicate, Pageable pageable); |
||||
|
||||
Long count(Predicate predicate); |
||||
} |
||||
---- |
||||
|
||||
To use this in your repository implementation, simply inherit from it in addition to other repository interfaces. This is shown below |
||||
|
||||
[source,java] |
||||
---- |
||||
public interface PersonRepository extends MongoRepository<Person, String>, QueryDslPredicateExecutor<Person> { |
||||
|
||||
// additional finder methods go here |
||||
} |
||||
---- |
||||
|
||||
We think you will find this an extremely powerful tool for writing MongoDB queries. |
||||
|
||||
[[mongodb.repositories.misc]] |
||||
== Miscellaneous |
||||
|
||||
[[mongodb.repositories.misc.cdi-integration]] |
||||
=== CDI Integration |
||||
|
||||
Instances of the repository interfaces are usually created by a container, which Spring is the most natural choice when working with Spring Data. As of version 1.3.0 Spring Data MongoDB ships with a custom CDI extension that allows using the repository abstraction in CDI environments. The extension is part of the JAR so all you need to do to activate it is dropping the Spring Data MongoDB JAR into your classpath. You can now set up the infrastructure by implementing a CDI Producer for the `MongoTemplate`: |
||||
|
||||
[source,java] |
||||
---- |
||||
class MongoTemplateProducer { |
||||
|
||||
@Produces |
||||
@ApplicationScoped |
||||
public MongoOperations createMongoTemplate() throws UnknownHostException, MongoException { |
||||
|
||||
MongoDbFactory factory = new SimpleMongoDbFactory(new Mongo(), "database"); |
||||
return new MongoTemplate(factory); |
||||
} |
||||
} |
||||
---- |
||||
|
||||
The Spring Data MongoDB CDI extension will pick up the `MongoTemplate` available as CDI bean and create a proxy for a Spring Data repository whenever an bean of a repository type is requested by the container. Thus obtaining an instance of a Spring Data repository is a matter of declaring an `@Inject`-ed property: |
||||
|
||||
[source,java] |
||||
---- |
||||
class RepositoryClient { |
||||
|
||||
@Inject |
||||
PersonRepository repository; |
||||
|
||||
public void businessMethod() { |
||||
List<Person> people = repository.findAll(); |
||||
} |
||||
} |
||||
---- |
||||
Loading…
Reference in new issue