您的位置:首页 > 数据库 > Mongodb

Spring Data MongoDB - Reference Documentation

2016-07-29 00:00 465 查看

Preface

TheSpringDataMongoDBprojectappliescoreSpringconceptstothedevelopmentofsolutionsusingtheMongoDBdocumentstyledatastore.Weprovidea"template"asahigh-levelabstractionforstoringandqueryingdocuments.YouwillnoticesimilaritiestotheJDBCsupportintheSpringFramework.

PartI.Introduction

ThisdocumentisthereferenceguideforSpringData-DocumentSupport.ItexplainsDocumentmoduleconceptsandsemanticsandthesyntaxforvariousstoresnamespaces.
ThissectionprovidessomebasicintroductiontoSpringandDocumentdatabase.TherestofthedocumentrefersonlytoSpringDataDocumentfeaturesandassumestheuserisfamiliarwithdocumentdatabasessuchasMongoDBandCouchDBaswellasSpringconcepts.

1.KnowingSpring

SpringDatausesSpringframework'scorefunctionality,suchastheIoCcontainer,typeconversionsystem,expressionlanguage,JMXintegration,andportableDAOexceptionhierarchy.WhileitisnotimportanttoknowtheSpringAPIs,understandingtheconceptsbehindthemis.Ataminimum,theideabehindIoCshouldbefamiliarforwhateverIoCcontaineryouchoosetouse.
ThecorefunctionalityoftheMongoDBandCouchDBsupportcanbeuseddirectly,withnoneedtoinvoketheIoCservicesoftheSpringContainer.ThisismuchlikeJdbcTemplatewhichcanbeused'standalone'withoutanyotherservicesoftheSpringcontainer.ToleverageallthefeaturesofSpringDatadocument,suchastherepositorysupport,youwillneedtoconfiguresomepartsofthelibraryusingSpring.
TolearnmoreaboutSpring,youcanrefertothecomprehensive(andsometimesdisarming)documentationthatexplainsindetailtheSpringFramework.Therearealotofarticles,blogentriesandbooksonthematter-takealookattheSpringframeworkhomepageformoreinformation.

2.KnowingNoSQLandDocumentdatabases

NoSQLstoreshavetakenthestorageworldbystorm.Itisavastdomainwithaplethoraofsolutions,termsandpatterns(tomakethingswortheventhetermitselfhasmultiplemeanings).Whilesomeoftheprinciplesarecommon,itiscrucialthattheuserisfamiliartosomedegreewiththestoressupportedbyDATADOC.Thebestwaytogetacquaintedtothissolutionsistoreadtheirdocumentationandfollowtheirexamples-itusuallydoesn'ttakemorethen5-10minutestogothroughthemandifyouarecomingfromanRDMBS-onlybackgroundmanytimestheseexercisescanbeaneyeopener.
ThejumpingoffgroundforlearningaboutMongoDBiswww.mongodb.org.Hereisalistofotherusefulresources.

TheonlineshellprovidesaconvenientwaytointeractwithaMongoDBinstanceincombinationwiththeonlinetutorial.

MongoDBJavaLanguageCenter

Severalbooksavailableforpurchase

KarlSeguin'sonlinebook:"TheLittleMongoDBBook"

Chapter1.WhySpringData-Document?

TheSpringFrameworkistheleadingfull-stackJava/JEEapplicationframework.Itprovidesalightweightcontainerandanon-invasiveprogrammingmodelenabledbytheuseofdependencyinjection,AOP,andportableserviceabstractions.
NoSQLstoragesprovideanalternativetoclassicalRDBMSforhorizontalscalabilityandspeed.Intermsofimplementation,DocumentstoresrepresentoneofthemostpopulartypesofstoresintheNoSQLspace.ThedocumentdatabasesupportedbySpringDataareMongoDBandCouchDB,thoughjustMongoDBintegrationhasbeenreleasedtodate.
ThegoaloftheSpringDataDocument(orDATADOC)frameworkistoprovideanextensiontotheSpringprogrammingmodelthatsupportswritingapplicationsthatuseDocumentdatabases.TheSpringframeworkhasalwayspromotedaPOJOprogrammingmodelwithastrongemphasisonportabilityandproductivity.ThesevaluesarecariedoverintoSpringDataDocument.
NotablefeaturesthatareusedinSpringDataDocumentfromtheSpringframeworkaretheFeaturesthatparticular,featuresfromtheSpringframeworkthatareusedaretheConversionService,JMXExporters,portableDataAccessExceptionhierarchy,SpringExpressionLanguage,andJavabasedIoCcontainerconfiguration.TheprogrammingmodelfollowsthefamiliarSpring'template'style,soifyouarefamilarwithSpringtemplateclassessuchasJdbcTemplate,JmsTemplate,RestTemplate,youwillfeelrightathome.Forexample,MongoTemplateremovesmuchoftheboilerplatecodeyouwouldhavetowritewhenusingtheMongoDBdrivertosavePOJOsaswellasarichjavabasedqueryinterfacetoretrievePOJOs.TheprogrammingmodelalsooffersanewRepositoryapproachinwhichtheSpringcontainerwillprovideanimplementationofaRepositorybasedsoleyoffaninterfacedefinitionwhichcanalsoincludecustomfindermethods.

Chapter2.Requirements

SpringDataDocument1.xbinariesrequiresJDKlevel6.0andabove,andSpringFramework3.0.xandabove.
Intermsofdocumentstores,MongoDBpreferablyversion1.6.5orlaterorCouchDB1.0.1orlaterarerequired.

Chapter3.AdditionalHelpResources

Learninganewframeworkisnotalwaysstraightforward.Inthissection,wetrytoprovidewhatwethinkisaneasytofollowguideforstartingwithSpringDataDocumentmodule.However,ifyouencounterissuesoryouarejustlookingforanadvice,feelfreetouseoneofthelinksbelow:

3.1.Support

Thereareafewsupportoptionsavailable:

3.1.1.CommunityForum

TheSpringDataforumisamessageboardforallSpringData(notjustDocument)userstoshareinformationandhelpeachother.Notethatregistrationisneededonlyforposting.

3.1.2.ProfessionalSupport

Professional,from-the-sourcesupport,withguaranteedresponsetime,isavailablefromSpringSource,thecompanybehindSpringDataandSpring.

3.2.FollowingDevelopment

ForinformationontheSpringDataMongosourcecoderepository,nightlybuildsandsnapshotartifactspleaseseetheSpringDataMongohomepage.
YoucanhelpmakeSpringDatabestservetheneedsoftheSpringcommunitybyinteractingwithdevelopersthroughtheSpringCommunityforums.TofollowdeveloperactivitylookforthemailinglistinformationontheSpringDataMongohomepage.
Ifyouencounterabugorwanttosuggestanimprovement,pleasecreateaticketontheSpringDataissuetracker.
TostayuptodatewiththelatestnewsandannouncementsintheSpringecosystem,subscribetotheSpringCommunityPortal.
Lastly,youcanfollowtheSpringSourceDatablogortheprojectteamonTwitter(SpringData)

Chapter4.Repositories

4.1.Introduction

Implementingadataaccesslayerofanapplicationhasbeencumbersomeforquiteawhile.Toomuchboilerplatecodehadtobewritten.Domainclasseswereanemicandnotdesignedinarealobjectorientedordomaindrivenmanner.
Usingbothofthesetechnologiesmakesdeveloperslifealoteasierregardingrichdomainmodel'spersistence.Neverthelesstheamountofboilerplatecodetoimplementrepositoriesespeciallyisstillquitehigh.SothegoaloftherepositoryabstractionofSpringDataistoreducetheefforttoimplementdataaccesslayersforvariouspersistencestoressignificantly.
ThefollowingchapterswillintroducethecoreconceptsandinterfacesofSpringDatarepositories.

4.2.Coreconcepts

ThecentralinterfaceinSpringDatarepositoryabstractionisRepository(probablynotthatmuchofasurprise).Itistypeabletothedomainclasstomanageaswellastheidtypeofthedomainclass.Thisinterfacemainlyactsasmarkerinterfacetocapturethetypestodealwithandhelpuswhendiscoveringinterfacesthatextendthisone.Beyondthatthere'sCrudRepositorywhichprovidessomesophisticatedfunctionalityaroundCRUDfortheentitybeingmanaged.

Example4.1.Repositoryinterface

publicinterfaceCrudRepository<T,IDextendsSerializable> extendsRepository<T,ID>{ Tsave(Tentity); TfindOne(IDprimaryKey); Iterable<T>findAll(); Longcount(); voiddelete(Tentity); booleanexists(IDprimaryKey); //…morefunctionalityomitted. }


Savesthegivenentity.

Returnstheentityidentifiedbythegivenid.

Returnsallentities.

Returnsthenumberofentities.

Deletesthegivenentity.

Returnswhetheranentitywiththegivenidexists.
Usuallywewillhavepersistencetechnologyspecificsub-interfacestoincludeadditionaltechnologyspecificmethods.WewillnowshipimplementationsforavarietyofSpringDatamodulesthatimplementthisinterface.
OntopoftheCrudRepositorythereisaPagingAndSortingRepositoryabstractionthataddsadditionalmethodstoeasepaginatedaccesstoentities:

Example4.2.PagingAndSortingRepository

publicinterfacePagingAndSortingRepository<T,IDextendsSerializable>extendsCrudRepository<T,ID>{ Iterable<T>findAll(Sortsort); Page<T>findAll(Pageablepageable); }

AccessingthesecondpageofUserbyapagesizeof20youcouldsimplydosomethinglikethis:
PagingAndSortingRepository<User,Long>repository=//…getaccesstoabean Page<User>users=repository.findAll(newPageRequest(1,20);

4.3.Querymethods

NexttostandardCRUDfunctionalityrepositoriesareusuallyqueriesontheunderlyingdatastore.WithSpringDatadeclaringthosequeriesbecomesafour-stepprocess:

DeclareaninterfaceextendingRepositoryoroneofitssub-interfacesandtypeittothedomainclassitshallhandle.publicinterfacePersonRepositoryextendsRepository<User,Long>{…}

Declarequerymethodsontheinterface.List<Person>findByLastname(Stringlastname);

SetupSpringtocreateproxyinstancesforthoseinterfaces.<?xmlversion="1.0"encoding="UTF-8"?> <beans:beansxmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/data/jpahttp://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <repositoriesbase-package="com.acme.repositories"/> </beans>

Gettherepositoryinstanceinjectedanduseit.publicclassSomeClient{ @Autowired privatePersonRepositoryrepository; publicvoiddoSomething(){ List<Person>persons=repository.findByLastname("Matthews"); }

Atthisstagewebarelyscratchedthesurfaceofwhat'spossiblewiththerepositoriesbutthegeneralapproachshouldbeclear.Let'sgothrougheachofthesestepsandfigureoutdetailsandvariousoptionsthatyouhaveateachstage.

4.3.1.Definingrepositoryinterfaces

Asaveryfirststepyoudefineadomainclassspecificrepositoryinterface.It'sgottoextendRepositoryandbetypedtothedomainclassandanIDtype.IfyouwanttoexposeCRUDmethodsforthatdomaintype,extendCrudRepositoryinsteadofRepository.

4.3.1.1.Finetuningrepositorydefinition

UsuallyyouwillhaveyourrepositoryinterfaceextendRepository,CrudRepositoryorPagingAndSortingRepository.Ifyoudon'tlikeextendingSpringDatainterfacesatallyoucanalsoannotateyourrepositoryinterfacewith@RepositoryDefinition.ExtendingCrudRepositorywillexposeacompletesetofmethodstomanipulateyourentities.Ifyouwouldratherbeselectiveaboutthemethodsbeingexposed,simplycopytheonesyouwanttoexposefromCrudRepositoryintoyourdomainrepository.

Example4.3.SelectivelyexposingCRUDmethods

interfaceMyBaseRepository<T,IDextendsSerializable>extendsRepository<T,ID>{ TfindOne(IDid); Tsave(Tentity); } interfaceUserRepositoryextendsMyBaseRepository<User,Long>{ UserfindByEmailAddress(EmailAddressemailAddress); }

InthefirststepwedefineacommonbaseinterfaceforallourdomainrepositoriesandexposefindOne(…)aswellassave(…).ThesemethodswillberoutedintothebaserepositoryimplementationofthestoreofyourchoicebecausetheyarematchingthemethodsignaturesinCrudRepository.SoourUserRepositorywillnowbeabletosaveusers,findsingleonesbyidaswellastriggeringaquerytofindUsersbytheiremailaddress.

4.3.2.Definingquerymethods

4.3.2.1.Querylookupstrategies

Thenextthingwehavetodiscussisthedefinitionofquerymethods.Therearetwomainwaysthattherepositoryproxyisabletocomeupwiththestorespecificqueryfromthemethodname.Thefirstoptionistoderivethequeryfromthemethodnamedirectly,thesecondisusingsomekindofadditionallycreatedquery.Whatdetailedoptionsareavailableprettymuchdependsontheactualstore,however,there'sgottobesomealgorithmthatdecideswhatactualqueryiscreated.
Therearethreestrategiesavailablefortherepositoryinfrastructuretoresolvethequery.Thestrategytobeusedcanbeconfiguredatthenamespacethroughthequery-lookup-strategyattribute.However,Itmightbethecasethatsomeofthestrategiesarenotsupportedforspecificdatastores.Hereareyouroptions:

CREATE

Thisstrategywilltrytoconstructastorespecificqueryfromthequerymethod'sname.Thegeneralapproachistoremoveagivensetofwell-knownprefixesfromthemethodnameandparsetherestofthemethod.ReadmoreaboutqueryconstructioninSection4.3.2.2,“Querycreation”.

USE_DECLARED_QUERY

Thisstrategytriestofindadeclaredquerywhichwillbeusedforexecutionfirst.Thequerycouldbedefinedbyanannotationsomewhereordeclaredbyothermeans.Pleaseconsultthedocumentationofthespecificstoretofindoutwhatoptionsareavailableforthatstore.Iftherepositoryinfrastructuredoesnotfindadeclaredqueryforthemethodatbootstraptimeitwillfail.

CREATE_IF_NOT_FOUND(default)

ThisstrategyisactuallyacombinationofCREATEandUSE_DECLARED_QUERY.Itwilltrytolookupadeclaredqueryfirstbutcreateacustommethodnamebasedqueryifnodeclaredquerywasfound.Thisisthedefaultlookupstrategyandthuswillbeusedifyoudon'tconfigureanythingexplicitly.Itallowsquickquerydefinitionbymethodnamesbutalsocustomtuningofthesequeriesbyintroducingdeclaredqueriesasneeded.

4.3.2.2.Querycreation

ThequerybuildermechanismbuiltintoSpringDatarepositoryinfrastructureisusefultobuildconstrainingqueriesoverentitiesoftherepository.WewillstriptheprefixesfindBy,find,readBy,read,getByaswellasgetfromthemethodandstartparsingtherestofit.AtaverybasiclevelyoucandefineconditionsonentitypropertiesandconcatenatethemwithANDandOR.

Example4.4.Querycreationfrommethodnames

publicinterfacePersonRepositoryextendsRepository<User,Long>{ List<Person>findByEmailAddressAndLastname(EmailAddressemailAddress,Stringlastname); }

Theactualresultofparsingthatmethodwillofcoursedependonthepersistencestorewecreatethequeryfor,however,therearesomegeneralthingstonotice.Theexpressionsareusuallypropertytraversalscombinedwithoperatorsthatcanbeconcatenated.AsyoucanseeintheexampleyoucancombinepropertyexpressionswithAndandOr.BeyondthatyoualsogetsupportforvariousoperatorslikeBetween,LessThan,GreaterThan,Likeforthepropertyexpressions.Astheoperatorssupportedcanvaryfromdatastoretodatastorepleaseconsulttheaccordingpartofthereferencedocumentation.

4.3.2.2.1.Propertyexpressions

Propertyexpressionscanjustrefertoadirectpropertyofthemanagedentity(asyoujustsawintheexampleabove).Onquerycreationtimewealreadymakesurethattheparsedpropertyisatapropertyofthemanageddomainclass.However,youcanalsodefineconstraintsbytraversingnestedproperties.AssumePersonshaveAddresseswithZipCodes.Inthatcaseamethodnameof
List<Person>findByAddressZipCode(ZipCodezipCode);
willcreatethepropertytraversalx.address.zipCode.Theresolutionalgorithmstartswithinterpretingtheentirepart(AddressZipCode)aspropertyandchecksthedomainclassforapropertywiththatname(uncapitalized).Ifitsucceedsitjustusesthat.Ifnotitstartssplittingupthesourceatthecamelcasepartsfromtherightsideintoaheadandatailandtriestofindtheaccordingproperty,e.g.AddressZipandCode.Ifwefindapropertywiththatheadwetakethetailandcontinuebuildingthetreedownfromthere.Asinourcasethefirstsplitdoesnotmatchwemovethesplitpointtotheleft(Address,ZipCode).
Althoughthisshouldworkformostcases,theremightbecaseswherethealgorithmcouldselectthewrongproperty.SupposeourPersonclasshasanaddressZippropertyaswell.Thenouralgorithmwouldmatchinthefirstsplitroundalreadyandessentiallychoosethewrongpropertyandfinallyfail(asthetypeofaddressZipprobablyhasnocodeproperty).Toresolvethisambiguityyoucanuse_insideyourmethodnametomanuallydefinetraversalpoints.Soourmethodnamewouldenduplikeso:
List<Person>findByAddress_ZipCode(ZipCodezipCode);

4.3.2.3.Specialparameterhandling

Tohandparameterstoyourqueryyousimplydefinemethodparametersasalreadyseenintheexamplesabove.Besidesthatwewillrecognizescertainspecifictypestoapplypaginationandsortingtoyourqueriesdynamically.

Example4.5.UsingPageableandSortinquerymethods

Page<User>findByLastname(Stringlastname,Pageablepageable); List<User>findByLastname(Stringlastname,Sortsort); List<User>findByLastname(Stringlastname,Pageablepageable);

ThefirstmethodallowsyoutopassaPageableinstancetothequerymethodtodynamicallyaddpagingtoyourstaticallydefinedquery.SortingoptionsarehandedviathePageableinstancetoo.Ifyouonlyneedsorting,simplyaddaSortparametertoyourmethod.Asyoualsocansee,simplyreturningaListispossibleaswell.WewillthennotretrievetheadditionalmetadatarequiredtobuildtheactualPageinstancebutrathersimplyrestrictthequerytolookuponlythegivenrangeofentities.


Note
Tofindouthowmanypagesyougetforaqueryentirelywehavetotriggeranadditionalcountquery.Thiswillbederivedfromthequeryyouactuallytriggerbydefault.

4.3.3.Creatingrepositoryinstances

Sonowthequestionishowtocreateinstancesandbeandefinitionsfortherepositoryinterfacesdefined.

4.3.3.1.Spring

TheeasiestwaytodosoisbyusingtheSpringnamespacethatisshippedwitheachSpringDatamodulethatsupportstherepositorymechanism.EachofthoseincludesarepositorieselementthatallowsyoutosimplydefineabasepackagethatSpringwillscanforyou.
<?xmlversion="1.0"encoding="UTF-8"?> <beans:beansxmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/data/jpahttp://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> <repositoriesbase-package="com.acme.repositories"/> </beans:beans>
InthiscaseweinstructSpringtoscancom.acme.repositoriesandallitssubpackagesforinterfacesextendingRepositoryoroneofitssub-interfaces.ForeachinterfacefounditwillregisterthepersistencetechnologyspecificFactoryBeantocreatetheaccordingproxiesthathandleinvocationsofthequerymethods.Eachofthesebeanswillberegisteredunderabeannamethatisderivedfromtheinterfacename,soaninterfaceofUserRepositorywouldberegisteredunderuserRepository.Thebase-packageattributeallowstheuseofwildcards,sothatyoucanhaveapatternofscannedpackages.

Usingfilters

BydefaultwewillpickupeveryinterfaceextendingthepersistencetechnologyspecificRepositorysub-interfacelocatedunderneaththeconfiguredbasepackageandcreateabeaninstanceforit.However,youmightwantfinergrainedcontroloverwhichinterfacesbeaninstancesgetcreatedfor.Todothiswesupporttheuseof<include-filter/>and<exclude-filter/>elementsinside<repositories/>.ThesemanticsareexactlyequivalenttotheelementsinSpring'scontextnamespace.FordetailsseeSpringreferencedocumentationontheseelements.
E.g.toexcludecertaininterfacesfrominstantiationasrepository,youcouldusethefollowingconfiguration:

Example4.6.Usingexclude-filterelement

<repositoriesbase-package="com.acme.repositories"> <context:exclude-filtertype="regex"expression=".*SomeRepository"/> </repositories>
ThiswouldexcludeallinterfacesendinginSomeRepositoryfrombeinginstantiated.

Manualconfiguration

Ifyou'dratherliketomanuallydefinewhichrepositoryinstancestocreateyoucandothiswithnested<repository/>elements.
<repositoriesbase-package="com.acme.repositories"> <repositoryid="userRepository"/> </repositories>

4.3.3.2.Standaloneusage

YoucanalsousetherepositoryinfrastructureoutsideofaSpringcontainerusage.YouwillstillneedtohavesomeoftheSpringlibrariesonyourclasspathbutyoucangenerallysetuprepositoriesprogrammaticallyaswell.TheSpringDatamodulesprovidingrepositorysupportshipapersistencetechnologyspecificRepositoryFactorythatcanbeusedasfollows:

Example4.7.Standaloneusageofrepositoryfactory

RepositoryFactorySupportfactory=…//Instantiatefactoryhere UserRepositoryrepository=factory.getRepository(UserRepository.class);

4.4.Customimplementations

4.4.1.Addingbehaviourtosinglerepositories

Oftenitisnecessarytoprovideacustomimplementationforafewrepositorymethods.SpringDatarepositorieseasilyallowyoutoprovidecustomrepositorycodeandintegrateitwithgenericCRUDabstractionandquerymethodfunctionality.Toenricharepositorywithcustomfunctionalityyouhavetodefineaninterfaceandanimplementationforthatfunctionalityfirstandlettherepositoryinterfaceyouprovidedsofarextendthatcustominterface.

Example4.8.Interfaceforcustomrepositoryfunctionality

interfaceUserRepositoryCustom{ publicvoidsomeCustomMethod(Useruser); }

Example4.9.Implementationofcustomrepositoryfunctionality

classUserRepositoryImplimplementsUserRepositoryCustom{ publicvoidsomeCustomMethod(Useruser){ //Yourcustomimplementation } }
NotethattheimplementationitselfdoesnotdependonSpringDataandcanbearegularSpringbean.Soyoucanusestandarddependencyinjectionbehaviourtoinjectreferencestootherbeans,takepartinaspectsandsoon.

Example4.10.Changestotheyourbasicrepositoryinterface

publicinterfaceUserRepositoryextendsCrudRepository<User,Long>,UserRepositoryCustom{ //Declarequerymethodshere }
Letyourstandardrepositoryinterfaceextendthecustomone.ThismakesCRUDandcustomfunctionalityavailabletoclients.

Configuration

Ifyouusenamespaceconfigurationtherepositoryinfrastructuretriestoautodetectcustomimplementationsbylookingupclassesinthepackagewefoundarepositoryusingthenamingconventionsappendingthenamespaceelement'sattributerepository-impl-postfixtotheclassname.ThissuffixdefaultstoImpl.

Example4.11.Configurationexample

<repositoriesbase-package="com.acme.repository"> <repositoryid="userRepository"/> </repositories> <repositoriesbase-package="com.acme.repository"repository-impl-postfix="FooBar"> <repositoryid="userRepository"/> </repositories>

Thefirstconfigurationexamplewilltrytolookupaclasscom.acme.repository.UserRepositoryImpltoactascustomrepositoryimplementation,wherethesecondexamplewilltrytolookupcom.acme.repository.UserRepositoryFooBar.

Manualwiring

TheapproachaboveworksperfectlywellifyourcustomimplementationusesannotationbasedconfigurationandautowiringentirelyasitwillbetreatedasanyotherSpringbean.Ifyourcustomimplementationbeanneedssomespecialwiringyousimplydeclarethebeanandnameitaftertheconventionsjustdescribed.Wewillthenpickupthecustombeanbynameratherthancreatinganinstance.

Example4.12.Manualwiringofcustomimplementations(I)

<repositoriesbase-package="com.acme.repository"> <repositoryid="userRepository"/> </repositories> <beans:beanid="userRepositoryImpl"class="…"> <!--furtherconfiguration--> </beans:bean>
Thisalsoworksifyouuseautomaticrepositorylookupwithoutdefiningsingle<repository/>elements.

Incaseyouarenotincontroloftheimplementationbeanname(e.g.ifyouwrapagenericrepositoryfacadearoundanexistingrepositoryimplementation)youcanexplicitlytellthe<repository/>elementwhichbeantouseascustomimplementationbyusingtherepository-impl-refattribute.

Example4.13.Manualwiringofcustomimplementations(II)

<repositoriesbase-package="com.acme.repository"> <repositoryid="userRepository"repository-impl-ref="customRepositoryImplementation"/> </repositories> <beanid="customRepositoryImplementation"class="…"> <!--furtherconfiguration--> </bean>

4.4.2.Addingcustombehaviourtoallrepositories

Inothercasesyoumightwanttoaddasinglemethodtoallofyourrepositoryinterfaces.Sotheapproachjustshownisnotfeasible.Thefirststeptoachievethisisaddingandintermediateinterfacetodeclarethesharedbehaviour

Example4.14.Aninterfacedeclaringcustomsharedbehaviour

publicinterfaceMyRepository<T,IDextendsSerializable> extendsJpaRepository<T,ID>{ voidsharedCustomMethod(IDid); }

Nowyourindividualrepositoryinterfaceswillextendthisintermediateinterfacetoincludethefunctionalitydeclared.Thesecondstepistocreateanimplementationofthisinterfacethatextendsthepersistencetechnologyspecificrepositorybaseclasswhichwillactascustombaseclassfortherepositoryproxiesthen.


Note
Ifyou'reusingautomaticrepositoryinterfacedetectionusingtheSpringnamespaceusingtheinterfacejustasiswillcauseSpringtocreateaninstanceofMyRepository.ThisisofcoursenotdesiredasitjustactsasintermediarybetweenRepositoryandtheactualrepositoryinterfacesyouwanttodefineforeachentity.ToexcludeaninterfaceextendingRepositoryfrombeinginstantiatedasrepositoryinstanceannotateitwith@NoRepositoryBean.
Example4.15.Customrepositorybaseclass

publicclassMyRepositoryImpl<T,IDextendsSerializable> extendsSimpleJpaRepository<T,ID>implementsMyRepository<T,ID>{ publicvoidsharedCustomMethod(IDid){ //implementationgoeshere } }

ThelaststeptogetthisimplementationusedasbaseclassforSpringDatarepositoriesisreplacingthestandardRepositoryFactoryBeanwithacustomoneusingacustomRepositoryFactorythatinturncreatesinstancesofyourMyRepositoryImplclass.

Example4.16.Customrepositoryfactorybean

publicclassMyRepositoryFactoryBean<TextendsJpaRepository<?,?> extendsJpaRepositoryFactoryBean<T>{ protectedRepositoryFactorySupportgetRepositoryFactory(…){ returnnewMyRepositoryFactory(…); } privatestaticclassMyRepositoryFactoryextendsJpaRepositoryFactory{ publicMyRepositoryImplgetTargetRepository(…){ returnnewMyRepositoryImpl(…); } publicClass<?extendsRepositorySupport>getRepositoryClass(){ returnMyRepositoryImpl.class; } } }

Finallyyoucaneitherdeclarebeansofthecustomfactorydirectlyorusethefactory-classattributeoftheSpringnamespacetotelltherepositoryinfrastructuretouseyourcustomfactoryimplementation.

Example4.17.Usingthecustomfactorywiththenamespace

<repositoriesbase-package="com.acme.repository" factory-class="com.acme.MyRepositoryFactoryBean"/>

4.5.Extensions

ThischapterdocumentsasetofSpringDataextensionsthatenableSpringDatausageinavarietyofcontexts.CurrentlymostoftheintegrationistargetedtowardsSpringMVC.

4.5.1.DomainclasswebbindingforSpringMVC

GivenyouaredevelopingaSpringMVCwebapplicationsyoutypicallyhavetoresolvedomainclassidsfromURLs.Bydefaultit'syourtasktotransformthatrequestparameterorURLpartintothedomainclasstohanditlayersbelowthenorexecutebusinesslogicontheentitiesdirectly.Thisshouldlooksomethinglikethis:
@Controller @RequestMapping("/users") publicclassUserController{ privatefinalUserRepositoryuserRepository; publicUserController(UserRepositoryuserRepository){ userRepository=userRepository; } @RequestMapping("/{id}") publicStringshowUserForm(@PathVariable("id")Longid,Modelmodel){ //Donullcheckforid Useruser=userRepository.findOne(id); //Donullcheckforuser //Populatemodel return"user"; } }
Firstyouprettymuchhavetodeclarearepositorydependencyforeachcontrollertolookuptheentitymanagedbythecontrollerorrepositoryrespectively.Beyondthatlookinguptheentityisboilerplateaswellasit'salwaysafindOne(…)call.FortunatelySpringprovidesmeanstoregistercustomconvertingcomponentsthatallowconversionbetweenaStringvaluetoanarbitrarytype.

PropertyEditors

ForversionsuptoSpring3.0simpleJavaPropertyEditorshadtobeused.Thus,weofferaDomainClassPropertyEditorRegistrar,thatwilllookupallSpringDatarepositoriesregisteredintheApplicationContextandregisteracustomPropertyEditorforthemanageddomainclass
<beanclass="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <propertyname="webBindingInitializer"> <beanclass="….web.bind.support.ConfigurableWebBindingInitializer"> <propertyname="propertyEditorRegistrars"> <beanclass="org.springframework.data.repository.support.DomainClassPropertyEditorRegistrar"/> </property> </bean> </property> </bean>
IfyouhaveconfiguredSpringMVClikethisyoucanturnyourcontrollerintothefollowingthatreducesalotoftheclutterandboilerplate.
@Controller @RequestMapping("/users") publicclassUserController{ @RequestMapping("/{id}") publicStringshowUserForm(@PathVariable("id")Useruser,Modelmodel){ //Donullcheckforuser //Populatemodel return"userForm"; } }

ConversionService

AsofSpring3.0thePropertyEditorsupportissuperseededbyanewconversioninfrstructurethatleavesallthedrawbacksofPropertyEditorsbehindandusesastatelessXtoYconversionapproach.WenowshipwithaDomainClassConverterthatprettymuchmimicsthebehaviourofDomainClassPropertyEditorRegistrar.ToregistertheconverteryouhavetodeclareConversionServiceFactoryBean,registertheconverterandtelltheSpringMVCnamespacetousetheconfiguredconversionservice:
<mvc:annotation-drivenconversion-service="conversionService"/> <beanid="conversionService"class="….context.support.ConversionServiceFactoryBean"> <propertyname="converters"> <list> <beanclass="org.springframework.data.repository.support.DomainClassConverter"> <constructor-argref="conversionService"/> </bean> </list> </property> </bean>

4.5.2.Webpagination

@Controller @RequestMapping("/users") publicclassUserController{ //DIcodeomitted @RequestMapping publicStringshowUsers(Modelmodel,HttpServletRequestrequest){ intpage=Integer.parseInt(request.getParameter("page")); intpageSize=Integer.parseInt(request.getParameter("pageSize")); model.addAttribute("users",userService.getUsers(pageable)); return"users"; } }
AsyoucanseethenaiveapproachrequiresthemethodtocontainanHttpServletRequestparameterthathastobeparsedmanually.Weevenomittedanappropriatefailurehandlingwhichwouldmakethecodeevenmoreverbose.Thebottomlineisthatthecontrolleractuallyshouldn'thavetohandlethefunctionalityofextractingpaginationinformationfromtherequest.SoweincludeaPageableArgumentResolverthatwilldotheworkforyou.
<beanclass="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <propertyname="customArgumentResolvers"> <list> <beanclass="org.springframework.data.web.PageableArgumentResolver"/> </list> </property> </bean>
Thisconfigurationallowsyoutosimplifycontrollersdowntosomethinglikethis:
@Controller @RequestMapping("/users") publicclassUserController{ @RequestMapping publicStringshowUsers(Modelmodel,Pageablepageable){ model.addAttribute("users",userDao.readAll(pageable)); return"users"; } }
ThePageableArgumentResolverwillautomaticallyresolverequestparameterstobuildaPageRequestinstance.Bydefaultitwillexpectthefollowingstructurefortherequestparameters:

Table4.1.RequestparametersevaluatedbyPageableArgumentResolver

pageThepageyouwanttoretrieve
page.sizeThesizeofthepageyouwanttoretrieve
page.sortThepropertythatshouldbesortedby
page.sort.dirThedirectionthatshouldbeusedforsorting
IncaseyouneedmultiplePageablestoberesolvedfromtherequest(formultipletablese.g.)youcanuseSpring's@Qualifierannotationtodistinguishonefromanother.Therequestparametersthenhavetobeprefixedwith${qualifier}_.Soamethodsignaturelikethis:
publicStringshowUsers(Modelmodel, @Qualifier("foo")Pageablefirst, @Qualifier("bar")Pageablesecond){…}
you'dhavetopopulatefoo_pageandbar_pageandtheaccordingsubproperties.

Defaulting

ThePageableArgumentResolverwilluseaPageRequestwiththefirstpageandapagesizeof10bydefaultandwillusethatincaseitcan'tresolveaPageRequestfromtherequest(becauseofmissingparameterse.g.).Youcanconfigureaglobaldefaultonthebeandeclarationdirectly.IncaseyoumightneedcontrollermethodspecificdefaultsforthePageablesimplyannotatethemethodparameterwith@PageableDefaultsandspecifypageandpagesizeasannotationattributes:
publicStringshowUsers(Modelmodel, @PageableDefaults(pageNumber=0,value=30)Pageablepageable){…}

PartII.ReferenceDocumentation

DocumentStructure

ThispartofthereferencedocumentationexplainsthecorefunctionalityofferedbySpringDataDocument.
Chapter5,MongoDBsupportintroducestheMongoDBmodulefeatureset.
Chapter6,MongoDBrepositoriesintroducestherepositorysupportforMongoDB.

Chapter5.MongoDBsupport

TheMongoDBsupportcontainsawiderangeoffeatureswhicharesummarizedbelow.

SpringconfigurationsupportusingJavabased@ConfigurationclassesoranXMLnamespaceforaMongodriverinstanceandreplicasets

MongoTemplatehelperclassthatincreasesproductivityperformingcommonMongooperations.IncludesintegratedobjectmappingbetweendocumentsandPOJOs.

ExceptiontranslationintoSpring'sportableDataAccessExceptionhierarchy

FeatureRichObjectMappingintegratedwithSpring'sConversionService

Annotationbasedmappingmetadatabutextensibletosupportothermetadataformats

Persistenceandmappinglifecycleevents

JavabasedQuery,Criteria,andUpdateDSLs

AutomaticimplementatinofRepositoryinterfacesincludingsupportforcustomfindermethods.

QueryDSLintegrationtosupporttype-safequeries.

Cross-storepersistance-supportforJPAEntitieswithfieldstransparentlypersisted/retrievedusingMongoDB

Log4jlogappender

GeoSpatialintegration

FormosttasksyouwillfindyourselfusingMongoTemplateortheRepositorysupportthatbothleveragetherichmappingfunctionality.MongoTemplateistheplacetolookforaccessingfunctionalitysuchasincrementingcountersorad-hocCRUDoperations.MongoTemplatealsoprovidescallbackmethodssothatitiseasyforyoutogetaholdofthelowlevelAPIartifactssuchasorg.mongo.DBtocommunicatedirectlywithMongoDB.ThegoalwithnamingconventionsonvariousAPIartifactsistocopythoseinthebaseMongoDBJavadriversoyoucaneasilymapyourexistingknowledgeontotheSpringAPIs.

5.1.GettingStarted

SpringMongoDBsupportrequiresMongoDB1.4orhigherandJavaSE5orhigher.Thelatestproductionrelease(2.0.xasofthiswriting)isrecommended.AneasywaytobootstrapsettingupaworkingenvironmentistocreateaSpringbasedprojectinSTS.
FirstyouneedtosetuparunningMongodbserver.RefertotheMongodbQuickStartguideforanexplanationonhowtostartupaMongoDBinstance.OnceinstalledstartingMongoDBistypicallyamatterofexecutingthefollowingcommand:MONGO_HOME/bin/mongod
TocreateaSpringprojectinSTSgotoFile->New->SpringTemplateProject->SimpleSpringUtilityProject-->pressYeswhenprompted.Thenenteraprojectandapackagenamesuchasorg.spring.mongodb.example.
Thenaddthefollowingtopom.xmldependenciessection.
<dependencies> <!--otherdependencyelementsomitted--> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>1.0.0.M5</version> </dependency> </dependencies>
AlsochangetheversionofSpringinthepom.xmltobe
<spring.framework.version>3.0.6.RELEASE</spring.framework.version>
YouwillalsoneedtoaddthelocationoftheSpringMilestonerepositoryformaventoyourpom.xmlwhichisatthesamelevelofyour<dependencies/>element
<repositories> <repository> <id>spring-milestone</id> <name>SpringMavenMILESTONERepository</name> <url>http://maven.springframework.org/milestone</url> </repository> </repositories>
Therepositoryisalsobrowseablehere.
YoumayalsowanttosettheloggingleveltoDEBUGtoseesomeadditionalinformation,editthelog4j.propertiesfiletohave
log4j.category.org.springframework.data.document.mongodb=DEBUG log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE}%5p%40.40c:%4L-%m%n
CreateasimplePersonclasstopersist
packageorg.spring.mongodb.example; publicclassPerson{ privateStringid; privateStringname; privateintage; publicPerson(Stringname,intage){ this.name=name; this.age=age; } publicStringgetId(){ returnid; } publicStringgetName(){ returnname; } publicintgetAge(){ returnage; } @Override publicStringtoString(){ return"Person[id="+id+",name="+name+",age="+age+"]"; } }
Andamainapplicationtorun
packageorg.spring.mongodb.example; importstaticorg.springframework.data.mongodb.core.query.Criteria.where; importorg.apache.commons.logging.Log; importorg.apache.commons.logging.LogFactory; importorg.springframework.data.mongodb.core.MongoOperations; importorg.springframework.data.mongodb.core.MongoTemplate; importorg.springframework.data.mongodb.core.query.Query; importcom.mongodb.Mongo; publicclassMongoApp{ privatestaticfinalLoglog=LogFactory.getLog(MongoApp.class); publicstaticvoidmain(String[]args)throwsException{ MongoOperationsmongoOps=newMongoTemplate(newMongo(),"database"); mongoOps.insert(newPerson("Joe",34)); log.info(mongoOps.findOne(newQuery(where("name").is("Joe")),Person.class)); mongoOps.dropCollection("person"); } }
Thiswillproducethefollowingoutput
10:01:32,062DEBUGapping.MongoPersistentEntityIndexCreator:80-Analyzingclassclassorg.spring.example.Personforindexinformation. 10:01:32,265DEBUGramework.data.mongodb.core.MongoTemplate:631-insertDBObjectcontainingfields:[_class,age,name]incollection:Person 10:01:32,765DEBUGramework.data.mongodb.core.MongoTemplate:1243-findOneusingquery:{"name":"Joe"}indb.collection:database.Person 10:01:32,953INFOorg.spring.mongodb.example.MongoApp:25-Person[id=4ddbba3c0be56b7e1b210166,name=Joe,age=34] 10:01:32,984DEBUGramework.data.mongodb.core.MongoTemplate:375-Droppedcollection[database.person]
Eveninthissimpleexample,therearefewthingstotakenoticeof

YoucaninstantiatethecentralhelperclassofSpringMongo,MongoTemplate,usingthestandardcom.mongodb.Mongoobjectandthenameofthedatabasetouse.

ThemapperworksagainststandardPOJOobjectswithouttheneedforanyadditionalmetadata(thoughyoucanoptionallyprovidethatinformation.Seehere.).

Conventionsareusedforhandlingtheidfield,convertingittobeaObjectIdwhenstoredinthedatabase.

Mappingconventionscanusefieldaccess.NoticethePersonclasshasonlygetters.

Iftheconstructorargumentnamesmatchthefieldnamesofthestoreddocument,theywillbeusedtoinstantiatetheobject

5.1.1.RequiredJars

ThefollowingjarsarerequiredtouseSpringDataMongoDB

spring-data-mongodb-1.0.2.RELEASE.jar

spring-data-commons-1.2.0.RELEASE.jar

InadditiontotheabovelistedSpringDatajarsyouneedtoprovidethefollowingdependencies:

aopalliance-1.0.0.jar

commons-logging-1.1.1.jar

mongo-java-driver-2.5.3.jar

spring-aop-3.0.7.RELEASE.jar

spring-asm-3.0.7.RELEASE.jar

spring-beans-3.0.7.RELEASE.jar

spring-context-3.0.7.RELEASE.jar

spring-core-3.0.7.RELEASE.jar

spring-expression-3.0.7.RELEASE.jar

5.1.2.MigratingfromM2toM3

TherewereseveralAPIchangesintroducedintheM3release.ToupgradefromM2toM3youwillneedtomake.ForafulllistingofAPIchangespleaserefertothisJDiffReport.
ThemajorchangesarewithrespecttoMongoTemplate

ConstructorshavechangedonMongoTemplate.MongoTemplate(Mongo,String,String)andMongoTemplate(Mongo,String,String,MongoConverter)wereremoved.MongoTemplate(Mongo,String,UserCredentials),MongoTemplate(MongoDbFactory),MongoTemplate(MongoDbFactory,MongoConverter)wereadded.ThesechangeswillalsoeffectusageofwiringupMongoTemplatein<bean/>XMLdefintions.

MongoTemplatenolongertakesadefaultcollectionname.ThecollectionnameisnoweitherspecifiedwhenthemethodisinvokedorinferredfromtheJavaclass,eithertheclassnameorviamappingmetadata.

ReorderedparametersinsomeMongoTemplatemethodstomakesignaturesmoreconsistentacrosstheboard.

RemovedMongoTemplatemethodsthatuseMongoReaderandMongoWriter.AsanalternativeregisteraSpringconverterwiththeMappingMongoConverter.Seeherefordetails.

AddedfindByIdmethodstoMongoTemplate.

5.2.ExamplesRepository

Thereisangithubrepositorywithseveralexamplesthatyoucandownloadandplayaroundwithtogetafeelforhowthelibraryworks.

5.3.ConnectingtoMongoDBwithSpring

OneofthefirsttaskswhenusingMongoDBandSpringistocreateacom.mongodb.MongoobjectusingtheIoCcontainer.Therearetwomainwaystodothis,eitherusingJavabasedbeanmetadataorXMLbasedbeanmetadata.Thesearediscussedinthefollowingsections.


Note
ForthosenotfamiliarwithhowtoconfiguretheSpringcontainerusingJavabasedbeanmetadatainsteadofXMLbasedmetadataseethehighlevelintroductioninthereferencedocshereaswellasthedetaileddocumentationhere.

5.3.1.RegisteringaMongoinstanceusingJavabasedmetadata

AnexampleofusingJavabasedbeanmetadatatoregisteraninstanceofacom.mongodb.Mongoisshownbelow

Example5.1.Registeringacom.mongodb.MongoobjectusingJavabasedbeanmetadata

@Configuration publicclassAppConfig{ /**UsethestandardMongodriverAPItocreateacom.mongodb.Mongoinstance.*/ public@BeanMongomongo()throwsUnknownHostException{ returnnewMongo("localhost"); } }

Thisapproachallowsyoutousethestandardcom.mongodb.MongoAPIthatyoumayalreadybeusedtousingbutalsopollutesthecodewiththeUnknownHostExceptioncheckedexception.TheuseofthecheckedexceptionisnotdesirableasJavabasedbeanmetadatausesmethodsasameanstosetobjectdependencies,makingthecallingcodecluttered.
Analternativeistoregisteraninstanceofcom.mongodb.MongoinstancewiththecontainerusingSpring'sMongoFactoryBean.Ascomparedtoinstantiatingacom.mongodb.Mongoinstancedirectly,theFactoryBeanapproachdoesnotthrowacheckedexceptionandhastheaddedadvantageofalsoprovidingthecontainerwithanExceptionTranslatorimplementationthattranslatesMongoDBexceptionstoexceptionsinSpring'sportableDataAccessExceptionhierarchyfordataaccessclassesannoatedwiththe@Repositoryannotation.Thishierarchyanduseof@RepositoryisdescribedinSpring'sDAOsupportfeatures.
AnexampleofaJavabasedbeanmetadatathatsupportsexceptiontranslationon@Repositoryannotatedclassesisshownbelow:

Example5.2.Registeringacom.mongodb.MongoobjectusingSpring'sMongoFactoryBeanandenablingSpring'sexceptiontranslationsupport

@Configuration
publicclassAppConfig{

/**Factorybeanthatcreatesthecom.mongodb.Mongoinstance*/
public@BeanMongoFactoryBeanmongo(){
MongoFactoryBeanmongo=newMongoFactoryBean();
mongo.setHost("localhost");
returnmongo;
}
}
Toaccessthecom.mongodb.MongoobjectcreatedbytheMongoFactoryBeaninother@Configurationoryourownclasses,usea"private@AutowiredMongomongo;"field.

5.3.2.RegisteringaMongoinstanceusingXMLbasedmetadata

WhileyoucanuseSpring'straditional<beans/>XMLnamespacetoregisteraninstanceofcom.mongodb.Mongowiththecontainer,theXMLcanbequiteverboseasitisgeneralpurpose.XMLnamespacesareabetteralternativetoconfiguringcommonlyusedobjectssuchastheMongoinstance.ThemongonamespacealowsyoutocreateaMongoinstanceserverlocation,replica-sets,andoptions.
TousetheMongonamespaceelementsyouwillneedtoreferencetheMongoschema:

Example5.3.XMLschematoconfigureMongoDB

<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns="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/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/data/mongohttp://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!--Defaultbeannameis'mongo'--> <mongo:mongohost="localhost"port="27017"/> </beans>

AmoreadvancedconfigurationwithMongoOptionsisshownbelow(notethesearenotrecommendedvalues)

Example5.4.XMLschematoconfigureacom.mongodb.MongoobjectwithMongoOptions

<beans> <mongo:mongohost="localhost"port="27017"> <mongo:optionsconnections-per-host="8" threads-allowed-to-block-for-connection-multiplier="4" connect-timeout="1000" max-wait-time="1500}" auto-connect-retry="true" socket-keep-alive="true" socket-timeout="1500" slave-ok="true" write-number="1" write-timeout="0" write-fsync="true"/> </mongo:mongo/> </beans>

Aconfigurationusingreplicasetsisshownbelow.

Example5.5.XMLschematoconfigurecom.mongodb.MongoobjectwithReplicaSets

<mongo:mongoid="replicaSetMongo"replica-set="127.0.0.1:27017,localhost:27018"/>

5.3.3.TheMongoDbFactoryinterface

Whilecom.mongodb.MongoistheentrypointtotheMongoDBdriverAPI,connectingtoaspecificMongoDBdatabaseinstancerequiresadditionalinformationsuchasthedatabasenameandanoptionalusernameandpassword.Withthatinformationyoucanobtainacom.mongodb.DBobjectandaccessallthefunctionalityofaspecificMongoDBdatabaseinstance.Springprovidestheorg.springframework.data.mongodb.core.MongoDbFactoryinterfaceshownbelowtobootstrapconnectivitytothedatabase.
publicinterfaceMongoDbFactory{ DBgetDb()throwsDataAccessException; DBgetDb(StringdbName)throwsDataAccessException; }
ThefollowingsectionsshowhowyoucanusethecontiainerwitheitherJavaortheXMLbasedmetadatatoconfigureaninstanceoftheMongoDbFactoryinterface.Inturn,youcanusetheMongoDbFactoryinstancetoconfigureMongoTemplate.
Theclassorg.springframework.data.mongodb.core.SimpleMongoDbFactoryprovidesimplementstheMongoDbFactoryinterfaceandiscreatedwithastandardcom.mongodb.Mongoinstance,thedatabasenameandanoptionalorg.springframework.data.authentication.UserCredentialsconstructorargument.
InsteadofusingtheIoCcontainertocreateaninstanceofMongoTemplate,youcanjustusetheminstandardJavacodeasshownbelow.
publicclassMongoApp{ privatestaticfinalLoglog=LogFactory.getLog(MongoApp.class); publicstaticvoidmain(String[]args)throwsException{ MongoOperationsmongoOps=newMongoTemplate(newSimpleMongoDbFactory(newMongo(),"database")); mongoOps.insert(newPerson("Joe",34)); log.info(mongoOps.findOne(newQuery(where("name").is("Joe")),Person.class)); mongoOps.dropCollection("person"); } }
ThecodeinboldhighlightstheuseofSimpleMongoDbFactoryandistheonlydifferencebetweenthelistingshowninthegettingstartedsection.

5.3.4.RegisteringaMongoDbFactoryinstanceusingJavabasedmetadata

ToregisteraMongoDbFactoryinstancewiththecontainer,youwritecodemuchlikewhatwashighlightedinthepreviouscodelisting.Asimpleexampleisshownbelow
@Configuration publicclassMongoConfiguration{ public@BeanMongoDbFactorymongoDbFactory()throwsException{ returnnewSimpleMongoDbFactory(newMongo(),"database"); } }
Todefinetheusernameandpasswordcreateaninstanceoforg.springframework.data.authentication.UserCredentialsandpassitintotheconstructorasshownbelow.ThislistingalsoshowsusingMongoDbFactoryregisteraninstanceofMongoTemplatewiththecontainer.
@Configuration publicclassMongoConfiguration{ public@BeanMongoDbFactorymongoDbFactory()throwsException{ UserCredentialsuserCredentials=newUserCredentials("joe","secret"); returnnewSimpleMongoDbFactory(newMongo(),"database",userCredentials); } public@BeanMongoTemplatemongoTemplate()throwsException{ returnnewMongoTemplate(mongoDbFactory()); } }

5.3.5.RegisteringaMongoDbFactoryinstanceusingXMLbasedmetadata

ThemongonamespaceprovidesaconvientwaytocreateaSimpleMongoDbFactoryascomparedtousingthe<beans/>namespace.Simpleusageisshownbelow
<mongo:db-factorydbname="database">
Intheaboveexampleacom.mongodb.Mongoinstanceiscreatedusingthedefaulthostandportnumber.TheSimpleMongoDbFactoryregisteredwiththecontainerisidentifiedbytheid'mongoDbFactory'unlessavaluefortheidattributeisspecified.
Youcanalsoprovidethehostandportfortheunderlyingcom.mongodb.Mongoinstanceasshownbelow,inadditiontousernameandpasswordforthedatabase.
<mongo:db-factoryid="anotherMongoDbFactory" host="localhost" port="27017" dbname="database" username="joe" password="secret"/>
Ifyouneedtoconfigureadditionaloptionsonthecom.mongodb.MongoinstancethatisusedtocreateaSimpleMongoDbFactoryyoucanrefertoanexistingbeanusingthemongo-refattributeasshownbelow.Toshowanothercommonusagepattern,thislistingshowtheuseofapropertyplaceholdertoparameterisetheconfigurationandcreatingMongoTemplate.
<context:property-placeholderlocation="classpath:/com/myapp/mongodb/config/mongo.properties"/> <mongo:mongohost="${mongo.host}"port="${mongo.port}"> <mongo:options connections-per-host="${mongo.connectionsPerHost}" threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}" connect-timeout="${mongo.connectTimeout}" max-wait-time="${mongo.maxWaitTime}" auto-connect-retry="${mongo.autoConnectRetry}" socket-keep-alive="${mongo.socketKeepAlive}" socket-timeout="${mongo.socketTimeout}" slave-ok="${mongo.slaveOk}" write-number="1" write-timeout="0" write-fsync="true"/> </mongo:mongo> <mongo:db-factorydbname="database"mongo-ref="mongo"/> <beanid="anotherMongoTemplate"class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-argname="mongoDbFactory"ref="mongoDbFactory"/> </bean>

5.4.IntroductiontoMongoTemplate

TheclassMongoTemplate,locatedinthepackageorg.springframework.data.document.mongodb,isthecentralclassoftheSpring'sMongoDBsupportprovidngarichfeaturesettointeractwiththedatabase.Thetemplateoffersconvenienceoperationstocreate,update,deleteandqueryforMongoDBdocumentsandprovidesamappingbetweenyourdomainobjectsandMongoDBdocuments.


Note
Onceconfigured,MongoTemplateisthread-safeandcanbereusedacrossmultipleinstances.
ThemappingbetweenMongoDBdocumentsanddomainclassesisdonebydelegatingtoanimplementationoftheinterfaceMongoConverter.Springprovidestwoimplementations,SimpleMappingConverterandMongoMappingConverter,butyoucanalsowriteyourownconverter.PleaserefertothesectiononMongoCovertersformoredetailedinformation.
TheMongoTemplateclassimplementstheinterfaceMongoOperations.Inasmuchaspossible,themethodsonMongoOperationsarenamedaftermethodsavailableontheMongoDBdriverCollectionobjectasastomaketheAPIfamiliartoexistingMongoDBdeveloperswhoareusedtothedriverAPI.Forexample,youwillfindmethodssuchas"find","findAndModify","findOne","insert","remove","save","update"and"updateMulti".ThedesigngoalwastomakeitaseasyaspossibletotransitionbetweentheuseofthebaseMongoDBdriverandMongoOperations.AmajordifferenceinbetweenthetwoAPIsisthatMongOperationscanbepasseddomainobjectsinsteadofDBObjectandtherearefluentAPIsforQuery,Criteria,andUpdateoperationsinsteadofpopulatingaDBObjecttospecifytheparametersforthoseoperatiosn.


Note
ThepreferredwaytoreferencetheoperationsonMongoTemplateinstanceisviaitsinterfaceMongoOperations.
ThedefaultconverterimplementationusedbyMongoTemplateisMongoMappingConverter.WhiletheMongoMappingConvertercanmakeuseofadditionalmetadatatospecifythemappingofobjectstodocumentsitisalsocapableofconvertingobjectsthatcontainnoadditonalmetadatabyusingsomeconventionsforthemappingofIDsandcollectionnames.TheseconventionsaswellastheuseofmappingannotationsisexplainedintheMappingchapter.


Note
IntheM2releaseSimpleMappingConverter,wasthedefaultandthisclassisnowdeprecatedasitsfunctionalityhasbeensubsumedbytheMongoMappingConverter.
AnothercentralfeatureofMongoTemplateisexceptiontranslationofexceptionsthrownintheMongoDBJavadriverintoSpring'sportableDataAccessExceptionhierarchy.Refertothesectiononexceptiontranslationformoreinformation.
WhiletherearemanyconveniencemethodsonMongoTemplatetohelpyoueasilyperformcommontasksifyoushouldneedtoaccesstheMongoDBdriverAPIdirectlytoaccessfunctionalitynotexplicitlyexposedbytheMongoTemplateyoucanuseoneofseveralExecutecallbackmethodstoaccessunderlyingdriverAPIs.Theexecutecallbackswillgiveyouareferencetoeitheracom.mongodb.Collectionoracom.mongodb.DBobject.PleaseseethesectionExecutionCallbacksformoreinformation.
Nowlet'slookataexamplesofhowtoworkwiththeMongoTemplateinthecontextoftheSpringcontainer.

5.4..InstantiatingMongoTemplate

YoucanuseJavatocreateandregisteraninstanceofMongoTemplateasshownbelow.

Example5.6.Registeringacom.mongodb.MongoobjectandenablingSpring'sexceptiontranslationsupport

@Configuration publicclassAppConfig{ public@BeanMongomongo()throwsException{ returnnewMongo("localhost"); } public@BeanMongoTemplatemongoTemplate()throwsException{ returnnewMongoTemplate(mongo(),"mydatabase"); } }

ThereareseveraloverloadedconstructorsofMongoTemplate.Theseare

MongoTemplate(Mongomongo,StringdatabaseName)-takesthecom.mongodb.Mongoobjectandthedefaultdatabasenametooperateagainst.

MongoTemplate(Mongomongo,StringdatabaseName,UserCredentialsuserCredentials)-addstheusernameandpasswordforauthenticatingwiththedatabase.

MongoTemplate(MongoDbFactorymongoDbFactory)-takesaMongoDbFactoryobjectthatencapsulatedthecom.mongodb.Mongoobject,databasename,andusernameandpassword.

MongoTemplate(MongoDbFactorymongoDbFactory,MongoConvertermongoConverter)-addsaMongoConvertertouseformapping.

YoucanalsoconfigureaMongoTemplateusingSpring'sXML<beans/>schema.
<mongo:mongohost="localhost"port="27017"/> <beanid="mongoTemplate"class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-argref="mongo"/> <constructor-argname="databaseName"value="geospatial"/> </bean>
OtheroptionalpropertiesthatyoumightliketosetwhencreatingaMongoTemplatearethedefaultWriteResultCheckingPolicy,WriteConcern,andReadPreference.


Note
ThepreferredwaytoreferencetheoperationsonMongoTemplateinstanceisviaitsinterfaceMongoOperations.

5.4..1.WriteResultCheckingPolicy

Whenindevelopmentitisveryhandytoeitherlogorthrowanexceptionifthecom.mongodb.WriteResultreturnedfromanyMongoDBoperationcontainsanerror.Itisquitecommontoforgettodothisduringdevelopmentandthenendupwithanapplicationthatlookslikeitrunssuccessfullybutinfactthedatabasewasnotmodifiedaccordingtoyourexpectations.SetMongoTemplate'sWriteResultCheckingpropertytoanenumwiththefollowingvalues,LOG,EXCEPTION,orNONEtoeitherlogtheerror,throwandexceptionordonothing.ThedefaultistouseaWriteResultCheckingvalueofNONE.

5.4..2.WriteConcern

Youcansetthecom.mongodb.WriteConcernpropertythattheMongoTemplatewilluseforwriteoperationsifithasnotyetbeenspecifiedviathedriveratahigherlevelsuchascom.mongodb.Mongo.IfMongoTemplate'sWriteConcernpropertyisnotsetitwilldefaulttotheonesetintheMongoDBdriver'sDBorCollectionsetting.

5.4..3.WriteConcernResolver

FormoreadvancedcaseswhereyouwanttosetdifferentWriteConcernvaluesonaper-operationbasis(forremove,update,insertandsaveoperations),astrategyinterfacecalledWriteConcernResolvercanbeconfiguredonMongoTemplate.SinceMongoTemplateisusedtopersistPOJOs,theWriteConcernResolverletsyoucreateapolicythatcanmapaspecificPOJOclasstoaWriteConcernvalue.TheWriteConcernResolverinterfaceisshownbelow.
publicinterfaceWriteConcernResolver{ WriteConcernresolve(MongoActionaction); }
Thepassedinargument,MongoAction,iswhatyouusetodeterminetheWriteConcernvaluetobeusedortousethevalueoftheTemplateitselfasadefault.MongoActioncontainsthecollectionnamebeingwrittento,thejava.lang.ClassofthePOJO,theconvertedDBObject,aswellastheoperationasanenumeration(MongoActionOperation:REMOVE,UPDATE,INSERT,INSERT_LIST,SAVE)andafewotherpiecesofcontextualinformation.Forexample,
privateclassMyAppWriteConcernResolverimplementsWriteConcernResolver{ publicWriteConcernresolve(MongoActionaction){ if(action.getEntityClass().getSimpleName().contains("Audit")){ returnWriteConcern.NONE; }elseif(action.getEntityClass().getSimpleName().contains("Metadata")){ returnWriteConcern.JOURNAL_SAFE; } returnaction.getDefaultWriteConcern(); } }

5.5.Saving,Updating,andRemovingDocuments

MongoTemplateprovidesasimplewayforyoutosave,update,anddeleteyourdomainobjectsandmapthoseobjectstodocumentsstoredinMongoDB.
GivenasimpleclasssuchasPerson
publicclassPerson{ privateStringid; privateStringname; privateintage; publicPerson(Stringname,intage){ this.name=name; this.age=age; } publicStringgetId(){ returnid; } publicStringgetName(){ returnname; } publicintgetAge(){ returnage; } @Override publicStringtoString(){ return"Person[id="+id+",name="+name+",age="+age+"]"; } }
Youcansave,updateanddeletetheobjectasshownbelow.


Note
MongoOperationsistheinterfacethatMongoTemplateimplements.
packageorg.spring.example; importstaticorg.springframework.data.mongodb.core.query.Criteria.where; importstaticorg.springframework.data.mongodb.core.query.Update.update; importstaticorg.springframework.data.mongodb.core.query.Query.query; importjava.util.List; importorg.apache.commons.logging.Log; importorg.apache.commons.logging.LogFactory; importorg.springframework.data.mongodb.core.MongoOperations; importorg.springframework.data.mongodb.core.MongoTemplate; importorg.springframework.data.mongodb.core.SimpleMongoDbFactory; importcom.mongodb.Mongo; publicclassMongoApp{ privatestaticfinalLoglog=LogFactory.getLog(MongoApp.class); publicstaticvoidmain(String[]args)throwsException{ MongoOperationsmongoOps=newMongoTemplate(newSimpleMongoDbFactory(newMongo(),"database")); Personp=newPerson("Joe",34); //Insertisusedtoinitiallystoretheobjectintothedatabase. mongoOps.insert(p); log.info("Insert:"+p); //Find p=mongoOps.findById(p.getId(),Person.class); log.info("Found:"+p); //Update mongoOps.updateFirst(query(where("name").is("Joe")),update("age",35),Person.class); p=mongoOps.findOne(query(where("name").is("Joe")),Person.class); log.info("Updated:"+p); //Delete mongoOps.remove(p); //Checkthatdeletionworked List<Person>people=mongoOps.findAll(Person.class); log.info("Numberofpeople=:"+people.size()); mongoOps.dropCollection(Person.class); } }
Thiswouldproducethefollowinglogoutput(includingdebugmessagesfromMongoTemplateitself)
DEBUGapping.MongoPersistentEntityIndexCreator:80-Analyzingclassclassorg.spring.example.Personforindexinformation. DEBUGwork.data.mongodb.core.MongoTemplate:632-insertDBObjectcontainingfields:[_class,age,name]incollection:person INFOorg.spring.example.MongoApp:30-Insert:Person[id=4ddc6e784ce5b1eba3ceaf5c,name=Joe,age=34] DEBUGwork.data.mongodb.core.MongoTemplate:1246-findOneusingquery:{"_id":{"$oid":"4ddc6e784ce5b1eba3ceaf5c"}}indb.collection:database.person INFOorg.spring.example.MongoApp:34-Found:Person[id=4ddc6e784ce5b1eba3ceaf5c,name=Joe,age=34] DEBUGwork.data.mongodb.core.MongoTemplate:778-callingupdateusingquery:{"name":"Joe"}andupdate:{"$set":{"age":35}}incollection:person DEBUGwork.data.mongodb.core.MongoTemplate:1246-findOneusingquery:{"name":"Joe"}indb.collection:database.person INFOorg.spring.example.MongoApp:39-Updated:Person[id=4ddc6e784ce5b1eba3ceaf5c,name=Joe,age=35] DEBUGwork.data.mongodb.core.MongoTemplate:823-removeusingquery:{"id":"4ddc6e784ce5b1eba3ceaf5c"}incollection:person INFOorg.spring.example.MongoApp:46-Numberofpeople=:0 DEBUGwork.data.mongodb.core.MongoTemplate:376-Droppedcollection[database.person]
TherewasimplicitconversionusingtheMongoConverterbetweenaStringandObjectIdasstoredinthedatabaseandrecognizingaconventionoftheproperty"Id"name.


Note
Thisexampleismeanttoshowtheuseofsave,updateandremoveoperationsonMongoTemplateandnottoshowcomplexmappingfunctionality
ThequerystynaxusedintheexampleisexplainedinmoredetailinthesectionQueryingDocuments.

5.5.1.Howthe'_id'fieldishandledinthemappinglayer

MongoDBrequiresthatyouhavean'_id'fieldforalldocuments.Ifyoudon'tprovideonethedriverwillassignaObjectIdwithageneratedvalue.WhenusingtheMongoMappingConvertertherearecertainrulesthatgovernhowpropertiesfromtheJavaclassismappedtothis'_id'field.
Thefollowingoutlineswhatpropertywillbemappedtothe'_id'documentfield:

Apropertyorfieldannotatedwith@Id(org.springframework.data.annotation.Id)willbemappedtothe'_id'field.

Apropertyorfieldwithoutanannotationbutnamedidwillbemappedtothe'_id'field.

Thefollowingoutlineswhattypeconversion,ifany,willbedoneonthepropertymappedtothe_iddocumentfieldwhenusingtheMappingMongoConverter,thedefaultforMongoTemplate.

AnidpropertyorfielddeclaredasaStringintheJavaclasswillbeconvertedtoandstoredasanObjectIdifpossibleusingaSpringConverter<String,ObjectId>.ValidconversionrulesaredelegatedtotheMongoDBJavadriver.IfitcannotbeconvertedtoanObjectId,thenthevaluewillbestoredasastringinthedatabase.

AnidpropertyorfielddeclaredasBigIntegerintheJavaclasswillbeconvertedtoandstoredasanObjectIdusingaSpringConverter<BigInteger,ObjectId>.

IfnofieldorpropertyspecifiedaboveispresentintheJavaclassthenanimplicit'_id'filewillbegeneratedbythedriverbutnotmappedtoapropertyorfieldoftheJavaclass.
WhenqueryingandupdatingMongoTemplatewillusetheconvertertohandleconversionsoftheQueryandUpdateobjectsthatcorrespondtotheaboverulesforsavingdocumentssofieldnamesandtypesusedinyourquerieswillbeabletomatchwhatisinyourdomainclasses.

5.5.2.Typemapping

AsMongoDBcollectionscancontaindocumentsthatrepresentinstancesofavarietyoftypes.AgreatexamplehereisifyoustoreahierarchyofclassesorsimplyhaveaclasswithapropertyoftypeObject.Inthelattercasethevaluesheldinsidethatpropertyhavetobereadincorrectlywhenretrievingtheobject.Thusweneedamechanismtostoretypeinformationalongsidetheactualdocument.
ToachievethattheMappingMongoConverterusesaMongoTypeMapperabstractionwithDefaultMongoTypeMapperasit'smainimplementation.It'sdefaultbehaviourisstoringthefullyqualifiedclassnameunder_classinsidethedocumentforthetop-leveldocumentaswellasforeveryvalueifit'sacomplextypeandasubtypeofthepropertytypedeclared.

Example5.7.Typemapping

publicclassSample{ Contactvalue; } publicabstractclassContact{…} publicclassPersonextendsContact{…} Samplesample=newSample(); sample.value=newPerson(); mongoTemplate.save(sample); {"_class":"com.acme.Sample", "value":{"_class":"com.acme.Person"} }

AsyoucanseewestorethetypeinformationfortheactualrootclasspersistetaswellasforthenestedtypeasitiscomplexandasubtypeofContact.Soifyou'renowusingmongoTemplate.findAll(Object.class,"sample")weareabletofindoutthatthedocumentstoredshallbeaSampleinstance.WearealsoabletofindoutthatthevaluepropertyshallbeaPersonactually.

Customizingtypemapping

IncaseyouwanttoavoidwritingtheentireJavaclassnameastypeinformationbutratherliketousesomekeyyoucanusethe@TypeAliasannotationattheentityclassbeingpersisted.IfyouneedtocustomizethemappingevenmorehavealookattheTypeInformationMapperinterface.AninstanceofthatinterfacecanbeconfiguredattheDefaultMongoTypeMapperwhichcanbeconfiguredinturnonMappingMongoConverter.

5.5.3.Methodsforsavingandinsertingdocuments

ThereareseveralconvenientmethodsonMongoTemplateforsavingandinsertingyourobjects.TohavemorefinegrainedcontrolovertheconversionprocessyoucanregisterSpringconverterswiththeMappingMongoConverter,forexampleConverter<Person,DBObject>andConverter<DBObject,Person>.


Note
Thedifferencebetweeninsertandsaveoperationsisthatasaveoperationwillperformaninsertiftheobjectisnotalreadypresent.
ThesimplecaseofusingthesaveoperationistosaveaPOJO.Inthiscasethecollectionnamewillbedeterminedbyname(notfullyqualfied)oftheclass.Youmayalsocallthesaveoperationwithaspecificcollectionname.Thecollectiontostoretheobjectcanbeoverridenusingmappingmetadata.
Wheninsertingorsaving,iftheIdpropertyisnotset,theassumptionisthatitsvaluewillbeautogeneratedbythedatabase.Assuch,forautogenerationofanObjectIdtosucceedthetypeoftheIdproperty/fieldinyourclassmustbeeitheraString,ObjectId,orBigInteger.
Hereisabasicexampleofusingthesaveoperationandretrievingitscontents.

Example5.8.InsertingandretrievingdocumentsusingtheMongoTemplate

importstaticorg.springframework.data.mongodb.core.query.Criteria.where; importstaticorg.springframework.data.mongodb.core.query.Criteria.query; … Personp=newPerson("Bob",33); mongoTemplate.insert(p); Personqp=mongoTemplate.findOne(query(where("age").is(33)),Person.class);

Theinsert/saveoperationsavailabletoyouarelistedbelow.

voidsave(ObjectobjectToSave)Savetheobjecttothedefaultcollection.

voidsave(ObjectobjectToSave,StringcollectionName)Savetheobjecttothespecifiedcollection.

Asimilarsetofinsertoperationsislistedbelow

voidinsert(ObjectobjectToSave)Inserttheobjecttothedefaultcollection.

voidinsert(ObjectobjectToSave,StringcollectionName)Inserttheobjecttothespecifiedcollection.

5.5.3.1.Whichcollectionwillmydocumentsbesavedinto?

Therearetwowaystomanagethecollectionnamethatisusedforoperatingonthedocuments.Thedefaultcollectionnamethatisusedistheclassnamechangedtostartwithalower-caseletter.Soacom.test.Personclasswouldbestoredinthe"person"collection.Youcancustomizethisbyprovidingadifferentcollectionnameusingthe@Documentannotation.YoucanalsooverridethecollectionnamebyprovidingyourowncollectionnameasthelastparameterfortheselectedMongoTemplatemethodcalls.

5.5.3.2.Insertingorsavingindividualobjects

TheMongoDBdriversupportsinsertingacollectionofdocumentsinoneoperation.ThemethodsintheMongoOperationsinterfacethatsupportthisfunctionalityarelistedbelow

insertInsertanobject.Ifthereisanexistingdocumentwiththesameidthenanerrorisgenerated.

insertAllTakesaCollectionofobjectsasthefirstparameter.Thismethodispectseachobjectandinsertsittotheappropriatecollectionbasedontherulesspecifiedabove.

saveSavetheobjectovewritinganyobjectthatmightexistwiththesameid.

5.5.3.3.Insertingseveralobjectsinabatch

TheMongoDBdriversupportsinsertingacollectionofdocumentsinoneoperation.ThemethodsintheMongoOperationsinterfacethatsupportthisfunctionalityarelistedbelow

insertmethodsthattakeaCollectionasthefirstargument.Thisinsertsalistofobjectsinasinglebatchwritetothedatabase.

5.5.4.Updatingdocumentsinacollection

ForupdateswecanelecttoupdatethefirstdocumentfoundusingMongoOperation'smethodupdateFirstorwecanupdatealldocumentsthatwerefoundtomatchthequeryusingthemethodupdateMulti.HereisanexampleofanupdateofallSAVINGSaccountswhereweareaddingaonetime$50.00bonustothebalanceusingthe$incoperator.

Example5.9.UpdatingdocumentsusingtheMongoTemplate

importstaticorg.springframework.data.mongodb.core.query.Criteria.where;
importstaticorg.springframework.data.mongodb.core.query.Query;
importstaticorg.springframework.data.mongodb.core.query.Update;

...

WriteResultwr=mongoTemplate.updateMulti(newQuery(where("accounts.accountType").is(Account.Type.SAVINGS)),
newUpdate().inc("accounts.$.balance",50.00),
Account.class);

InadditiontotheQuerydiscussedaboveweprovidetheupdatedefinitionusinganUpdateobject.TheUpdateclasshasmethodsthatmatchtheupdatemodifiersavailableforMongoDB.
AsyoucanseemostmethodsreturntheUpdateobjecttoprovideafluentstylefortheAPI.

5.5.4.1.Methodsforexecutingupdatesfordocuments

updateFirstUpdatesthefirstdocumentthatmatchesthequerydocumentcriteriawiththeprovidedupdateddocument.

updateMultiUpdatesallobjectsthatmatchthequerydocumentcriteriawiththeprovidedupdateddocument.

5.5.4.2.MethodsfortheUpdateclass

TheUpdateclasscanbeusedwithalittle'syntaxsugar'asitsmethodsaremeanttobechainedtogetherandyoucankickstartthecreationofanewUpdateinstanceviathestaticmethodpublicstaticUpdateupdate(Stringkey,Objectvalue)andusingstaticimports.
HereisalistingofmethodsontheUpdateclass

UpdateaddToSet(Stringkey,Objectvalue)Updateusingthe$addToSetupdatemodifier

Updateinc(Stringkey,Numberinc)Updateusingthe$incupdatemodifier

Updatepop(Stringkey,Update.Positionpos)Updateusingthe$popupdatemodifier

Updatepull(Stringkey,Objectvalue)Updateusingthe$pullupdatemodifier

UpdatepullAll(Stringkey,Object[]values)Updateusingthe$pullAllupdatemodifier

Updatepush(Stringkey,Objectvalue)Updateusingthe$pushupdatemodifier

UpdatepushAll(Stringkey,Object[]values)Updateusingthe$pushAllupdatemodifier

Updaterename(StringoldName,StringnewName)Updateusingthe$renameupdatemodifier

Updateset(Stringkey,Objectvalue)Updateusingthe$setupdatemodifier

Updateunset(Stringkey)Updateusingthe$unsetupdatemodifier

5.5.5.Upsertingdocumentsinacollection

RelatedtoperfomringanupdateFirstoperations,youcanalsoperformanupsertoperationwhichwillperformaninsertifnodocumentisfoundthatmatchesthequery.Thedocumentthatisinsertedisacombinationofthequerydocumentandtheupdatedocument.Hereisanexample
template.upsert(query(where("ssn").is(1111).and("firstName").is("Joe").and("Fraizer").is("Update")),update("address",addr),Person.class);

5.5.6.FindingandUpsertingdocumentsinacollection

ThefindAndModify(…)methodonDBCollectioncanupdateadocumentandreturneithertheoldornewlyupdateddocumentinasingleoperation.MongoTemplateprovidesafindAndModifymethodthattakesQueryandUpdateclassesandconvertsfromDBObjecttoyourPOJOs.Herearethemethods
<T>TfindAndModify(Queryquery,Updateupdate,Class<T>entityClass);

<T>TfindAndModify(Queryquery,Updateupdate,Class<T>entityClass,StringcollectionName);

<T>TfindAndModify(Queryquery,Updateupdate,FindAndModifyOptionsoptions,Class<T>entityClass);

<T>TfindAndModify(Queryquery,Updateupdate,FindAndModifyOptionsoptions,Class<T>entityClass,StringcollectionName);
Asanexampleusage,wewillinsertoffewPersonobjectsintothecontainerandperformasimplefindAndUpdateoperation
mongoTemplate.insert(newPerson("Tom",21));
mongoTemplate.insert(newPerson("Dick",22));
mongoTemplate.insert(newPerson("Harry",23));

Queryquery=newQuery(Criteria.where("firstName").is("Harry"));
Updateupdate=newUpdate().inc("age",1);
Personp=mongoTemplate.findAndModify(query,update,Person.class);//return'soldpersonobject

assertThat(p.getFirstName(),is("Harry"));
assertThat(p.getAge(),is(23));
p=mongoTemplate.findOne(query,Person.class);
assertThat(p.getAge(),is(24));

//Nowreturnthenewlyupdateddocumentwhenupdating
p=template.findAndModify(query,update,newFindAndModifyOptions().returnNew(true),Person.class);
assertThat(p.getAge(),is(25));
TheFindAndModifyOptionsletsyousettheoptionsofreturnNew,upsert,andremove.Anexampleextendingoffthepreviouscodesnippitisshownbelow
Queryquery2=newQuery(Criteria.where("firstName").is("Mary"));
p=mongoTemplate.findAndModify(query2,update,newFindAndModifyOptions().returnNew(true).upsert(true),Person.class);
assertThat(p.getFirstName(),is("Mary"));
assertThat(p.getAge(),is(1));

5.5.7.Methodsforremovingdocuments

Youcanuseseveraloverloadedmethodstoremoveanobjectfromthedatabase.

removeRemovethegivendocumentbasedononeofthefollowing:aspecificobjectinstance,aquerydocumentcriteriacombinedwithaclassoraquerydocumentcriteriacombinedwithaspecificcollectionname.

5.6.QueryingDocuments

YoucanexpressyourqueriesusingtheQueryandCriteriaclasseswhichhavemethodnamesthatmirrorthenativeMongoDBoperatornamessuchaslt,lte,is,andothers.TheQueryandCriteriaclassesfollowafluentAPIstylesothatyoucaneasilychaintogethermultiplemethodcriteriaandquerieswhilehavingeasytounderstandcode.StaticimportsinJavaareusedtohelpremovetheneedtoseethe'new'keywordforcreatingQueryandCriteriainstancessoastoimprovereadability.IfyouliketocreateQueryinstancesfromaplainJSONStringuseBasicQuery.

Example5.10.CreatingaQueryinstancefromaplainJSONString

BasicQueryquery=newBasicQuery("{age:{$lt:50},accounts.balance:{$gt:1000.00}}");
List<Person>result=mongoTemplate.find(query,Person.class);

GeoSpatialqueriesarealsosupportedandaredescribedmoreinthesectionGeoSpatialQueries.
Map-ReduceoperationsarealsosupportedandaredescribedmoreinthesectionMap-Reduce.

5.6.1.Queryingdocumentsinacollection

WesawhowtoretrieveasingledocumentusingthefindOneandfindByIdmethodsonMongoTemplateinprevioussectionswhichreturnasingledomainobject.Wecanalsoqueryforacollectionofdocumentstobereturnedasalistofdomainobjects.AssumingthatwehaveanumberofPersonobjectswithnameandagestoredasdocumentsinacollectionandthateachpersonhasanembeddedaccountdocumentwithabalance.Wecannowrunaqueryusingthefollowingcode.

Example5.11.QueryingfordocumentsusingtheMongoTemplate

importstaticorg.springframework.data.mongodb.core.query.Criteria.where;
importstaticorg.springframework.data.mongodb.core.query.Query.query;



List<Person>result=mongoTemplate.find(query(where("age").lt(50)
.and("accounts.balance").gt(1000.00d)),Person.class);

AllfindmethodstakeaQueryobjectasaparameter.Thisobjectdefinesthecriteriaandoptionsusedtoperformthequery.ThecriteriaisspecifiedusingaCriteriaobjectthathasastaticfactorymethodnamedwhereusedtoinstantiateanewCriteriaobject.Werecommendusingastaticimportfororg.springframework.data.mongodb.core.query.Criteria.whereandQuery.querytomakethequerymorereadable.
ThisqueryshouldreturnalistofPersonobjectsthatmeetthespecifiedcriteria.TheCriteriaclasshasthefollowingmethodsthatcorrespondtotheoperatorsprovidedinMongoDB.
AsyoucanseemostmethodsreturntheCriteriaobjecttoprovideafluentstylefortheAPI.

5.6.1.1.MethodsfortheCriteriaclass

Criteriaall(Objecto)Createsacriterionusingthe$alloperator

Criteriaand(Stringkey)AddsachainedCriteriawiththespecifiedkeytothecurrentCriteriaandretunsthenewlycreatedone

CriteriaandOperator(Criteria...criteria)Createsanandqueryusingthe$andoperatorforalloftheprovidedcriteria(requiresMongoDB2.0orlater)

CriteriaelemMatch(Criteriac)Createsacriterionusingthe$elemMatchoperator

Criteriaexists(booleanb)Createsacriterionusingthe$existsoperator

Criteriagt(Objecto)Createsacriterionusingthe$gtoperator

Criteriagte(Objecto)Createsacriterionusingthe$gteoperator

Criteriain(Object...o)Createsacriterionusingthe$inoperatorforavarargsargument.

Criteriain(Collection<?>collection)Createsacriterionusingthe$inoperatorusingacollection

Criteriais(Objecto)Createsacriterionusingthe$isoperator

Criterialt(Objecto)Createsacriterionusingthe$ltoperator

Criterialte(Objecto)Createsacriterionusingthe$lteoperator

Criteriamod(Numbervalue,Numberremainder)Createsacriterionusingthe$modoperator

Criteriane(Objecto)Createsacriterionusingthe$neoperator

Criterianin(Object...o)Createsacriterionusingthe$ninoperator

CriterianorOperator(Criteria...criteria)Createsannorqueryusingthe$noroperatorforalloftheprovidedcriteria

Criterianot()Createsacriterionusingthe$notmetaoperatorwhichaffectstheclausedirectlyfollowing

CriteriaorOperator(Criteria...criteria)Createsanorqueryusingthe$oroperatorforalloftheprovidedcriteria

Criteriaregex(Stringre)Createsacriterionusinga$regex

Criteriasize(ints)Createsacriterionusingthe$sizeoperator

Criteriatype(intt)Createsacriterionusingthe$typeoperator

TherearealsomethodsontheCriteriaclassforgeospatialqueries.HereisalistingbutlookatthesectiononGeoSpatialQueriestoseetheminaction.

CriteriawithinCenter(Circlecircle)Createsageospatialcriterionusing$within$centeroperators

CriteriawithinCenterSphere(Circlecircle)Createsageospatialcriterionusing$within$centeroperators.ThisisonlyavailableforMongoDB1.7andhigher.

CriteriawithinBox(Boxbox)Createsageospatialcriterionusinga$within$boxoperation

Criterianear(Pointpoint)Createsageospatialcriterionusinga$nearoperation

CriterianearSphere(Pointpoint)Createsageospatialcriterionusing$nearSphere$centeroperations.ThisisonlyavailableforMongoDB1.7andhigher.

CriteriamaxDistance(doublemaxDistance)Createsageospatialcriterionusingthe$maxDistanceoperation,forusewith$near.

TheQueryclasshassomeadditionalmethodsusedtoprovideoptionsforthequery.

5.6.1.2.MethodsfortheQueryclass

QueryaddCriteria(Criteriacriteria)usedtoaddadditionalcriteriatothequery

Fieldfields()usedtodefinefieldstobeincludedinthequeryresults

Querylimit(intlimit)usedtolimitthesizeofthereturnedresultstotheprovidedlimit(usedforpaging)

Queryskip(intskip)usedtoskiptheprovidednumberofdocumentsintheresults(usedforpaging)

Sortsort()usedtoprovidesortdefinitionfortheresults

5.6.2.Methodsforqueryingfordocuments

ThequerymethodsneedtospecifythetargettypeTthatwillbereturnedandtheyarealsooverloadedwithanexplicitcollectionnameforqueriesthatshouldoperateonacollectionotherthantheoneindicatedbythereturntype.

findAllQueryforalistofobjectsoftypeTfromthecollection.

findOneMaptheresultsofanad-hocqueryonthecollectiontoasingleinstanceofanobjectofthespecifiedtype.

findByIdReturnanobjectofthegivenidandtargetclass.

findMaptheresultsofanad-hocqueryonthecollectiontoaListofthespecifiedtype.

findAndRemoveMaptheresultsofanad-hocqueryonthecollectiontoasingleinstanceofanobjectofthespecifiedtype.Thefirstdocumentthatmatchesthequeryisreturnedandalsoremovedfromthecollectioninthedatabase.

5.6.3.GeoSpatialQueries

MongoDBsupportsGeoSpatialqueriesthroughtheuseofoperatorssuchas$near,$within,and$nearSphere.MethodsspecifictogeospatialqueriesareavailableontheCriteriaclass.Therearealsoafewshapeclasses,Box,Circle,andPointthatareusedinconjunctionwithgeospatialrelatedCriteriamethods.
TounderstandhowtoperformGeoSpatialquerieswewillusethefollowingVenueclasstakenfromtheintegrationtests.whichreliesonusingtherichMappingMongoConverter.
@Document(collection="newyork")
publicclassVenue{

@Id
privateStringid;
privateStringname;
privatedouble[]location;

@PersistenceConstructor
Venue(Stringname,double[]location){
super();
this.name=name;
this.location=location;
}

publicVenue(Stringname,doublex,doubley){
super();
this.name=name;
this.location=newdouble[]{x,y};
}

publicStringgetName(){
returnname;
}

publicdouble[]getLocation(){
returnlocation;
}

@Override
publicStringtoString(){
return"Venue[id="+id+",name="+name+",location="
+Arrays.toString(location)+"]";
}
}
TofindlocationswithinaCircle,thefollowingquerycanbeused.
Circlecircle=newCircle(-73.99171,40.738868,0.01);
List<Venue>venues=
template.find(newQuery(Criteria.where("location").withinCenter(circle)),Venue.class);
TofindvenueswithinaCircleusingsphericalcoordinatesthefollowingquerycanbeused
Circlecircle=newCircle(-73.99171,40.738868,0.003712240453784);
List<Venue>venues=
template.find(newQuery(Criteria.where("location").withinCenterSphere(circle)),Venue.class);
TofindvenueswithinaBoxthefollowingquerycanbeused
//lower-leftthenupper-right
Boxbox=newBox(newPoint(-73.99756,40.73083),newPoint(-73.988135,40.741404));
List<Venue>venues=
template.find(newQuery(Criteria.where("location").withinBox(box)),Venue.class);
TofindvenuesnearaPoint,thefollowingquerycanbeused
Pointpoint=newPoint(-73.99171,40.738868);
List<Venue>venues=
template.find(newQuery(Criteria.where("location").near(point).maxDistance(0.01)),Venue.class);
TofindvenuesnearaPointusingsphericalcoordinesthefollowingquerycanbeused
Pointpoint=newPoint(-73.99171,40.738868);
List<Venue>venues=
template.find(newQuery(
Criteria.where("location").nearSphere(point).maxDistance(0.003712240453784)),
Venue.class);

5.6.3.1.Geonearqueries

MongoDBsupportsqueryingthedatabaseforgeolocationsandcalculationthedistancefromagivenoriginattheverysametime.Withgeo-nearqueriesit'spossibletoexpressquerieslike:"findallrestaurantsinthesurrounding10miles".TodosoMongoOperationsprovidesgeoNear(…)methodstakingaNearQueryasargumentaswellasthealreadyfamiliarentitytypeandcollection
Pointlocation=newPoint(-73.99171,40.738868);
NearQueryquery=NearQuery.near(location).maxDistance(newDistance(10,Metrics.MILES));

GeoResults<Restaurant>=operations.geoNear(query,Restaurant.class);
AsyoucanseeweusetheNearQuerybuilderAPItosetupaquerytoreturnallRestaurantinstancessurroundingthegivenPointby10milesmaximum.TheMetricsenumusedhereactuallyimplementsaninterfacesothatothermetricscouldbepluggedintoadistanceaswell.AMetricisbackedbyamultipliertotransformthedistancevalueofthegivenmetricintonativedistances.Thesampleshownherewouldconsiderthe10tobemiles.Usingoneofthepre-builtinmetrics(milesandkilometers)willautomaticallytriggerthesphericalflagtobesetonthequery.Ifyouwanttoavoidthat,simplyhandinplaindoublevaluesintomaxDistance(…).FormoreinformationseetheJavaDocofNearQueryandDistance.
ThegeonearoperationsreturnaGeoResultswrapperobjectthatencapsulatesGeoResultinstances.ThewrappingGeoResultsallowstoaccesstheaveragedistanceofallresults.AsingleGeoResultobjectsimplycarriestheentityfoundplusitsdistancefromtheorigin.

5.7.Map-ReduceOperations

YoucanqueryMongoDBusingMap-Reducewhichisusefulforbatchprocessing,dataaggregation,andforwhenthequerylanguagedoesn'tfulfillyourneeds.
SpringprovidesintegrationwithMongoDB'smapreducebyprovidingmethodsonMongoOperationstosimplifythecreationandexecutionofMap-Reduceoperations.ItcanconverttheresultsofaMap-ReduceoperationtoaPOJOalsointegrateswithSpring'sResourceabstractionabstraction.ThiswillletyouplaceyourJavaScriptfilesonthefilesystem,classpath,httpserveroranyotherSpringResourceimplementationandthenreferencetheJavaScriptresourcesviaaneasyURIstylesyntax,e.g.'classpath:reduce.js;.ExternalizingJavaScriptcodeinfilesisoftenpreferabletoembeddingthemasJavastringsinyourcode.NotethatyoucanstillpassJavaScriptcodeasJavastringsifyouprefer.

5.7.1.ExampleUsage

TounderstandhowtoperformMap-Reduceoperationsanexamplefromthebook'MongoDB-Thedefinitiveguide'isused.Inthisexamplewewillcreatethreedocumentsthathavethevalues[a,b],[b,c],and[c,d]respectfully.Thevaluesineachdocumentareassociatedwiththekey'x'asshownbelow.Forthisexampleassumethesedocumentsareinthecollectionnamed"jmr1".
{"_id":ObjectId("4e5ff893c0277826074ec533"),"x":["a","b"]}
{"_id":ObjectId("4e5ff893c0277826074ec534"),"x":["b","c"]}
{"_id":ObjectId("4e5ff893c0277826074ec535"),"x":["c","d"]}
Amapfunctionthatwillcounttheoccuranceofeachletterinthearrayforeachdocumentisshownbelow
function(){
for(vari=0;i<this.x.length;i++){
emit(this.x[i],1);
}
}
Thereducefunctionthatwillsumuptheoccuranceofeachletteracrossallthedocumentsisshownbelow
function(key,values){
varsum=0;
for(vari=0;i<values.length;i++)
sum+=values[i];
returnsum;
}
Executingthiswillresultinacollectionasshownbelow.
{"_id":"a","value":1}
{"_id":"b","value":2}
{"_id":"c","value":2}
{"_id":"d","value":1}
Assumingthatthemapandreducefunctionsarelocatedinmap.jsandreduce.jsandbundledinyourjarsotheyareavailableontheclasspath,youcanexecuteamap-reduceoperationandobtaintheresultsasshownbelow
MapReduceResults<ValueObject>results=mongoOperations.mapReduce("jmr1","classpath:map.js","classpath:reduce.js",ValueObject.class);
for(ValueObjectvalueObject:results){
System.out.println(valueObject);
}
Theoutputoftheabovecodeis
ValueObject[id=a,value=1.0]
ValueObject[id=b,value=2.0]
ValueObject[id=c,value=2.0]
ValueObject[id=d,value=1.0]
TheMapReduceResultsclassimplementsIterableandprovidesaccesstotherawoutput,aswellastimingandcountstatistics.TheValueObjectclassissimply
publicclassValueObject{

privateStringid;
privatefloatvalue;

publicStringgetId(){
returnid;
}

publicfloatgetValue(){
returnvalue;
}

publicvoidsetValue(floatvalue){
this.value=value;
}

@Override
publicStringtoString(){
return"ValueObject[id="+id+",value="+value+"]";
}
}
BydefaulttheoutputtypeofINLINEisusedsoyoudon'thavetospecifyanoutputcollection.Tospecifyadditionalmap-reduceoptionsuseanoverloadedmethodthattakesanadditionalMapReduceOptionsargument.TheclassMapReduceOptionshasafluentAPIsoaddingadditionaloptionscanbedoneinaverycompactsyntax.Hereanexamplethatsetstheoutputcollectionto"jmr1_out".NotethatsettingonlytheoutputcollectionassumesadefaultoutputtypeofREPLACE.
MapReduceResults<ValueObject>results=mongoOperations.mapReduce("jmr1","classpath:map.js","classpath:reduce.js",
newMapReduceOptions().outputCollection("jmr1_out"),ValueObject.class);
Thereisalsoastaticimportimportstaticorg.springframework.data.mongodb.core.mapreduce.MapReduceOptions.options;thatcanbeusedtomakethesyntaxslightlymorecompact
MapReduceResults<ValueObject>results=mongoOperations.mapReduce("jmr1","classpath:map.js","classpath:reduce.js",
options().outputCollection("jmr1_out"),ValueObject.class);
Youcanalsospecifyaquerytoreducethesetofdatathatwillbeusedtofeedintothemap-reduceoperation.Thiswillremovethedocumentthatcontains[a,b]fromconsiderationformap-reduceoperations.
Queryquery=newQuery(where("x").ne(newString[]{"a","b"}));
MapReduceResults<ValueObject>results=mongoOperations.mapReduce(query,"jmr1","classpath:map.js","classpath:reduce.js",
options().outputCollection("jmr1_out"),ValueObject.class);
Notethatyoucanspecifyadditionallimitandsortvaluesaswellonthequerybutnotskipvalues.

5.8.GroupOperations

AsanalternativetousiingMap-Reducetoperformdataaggregation,youcanusethegroupoperationwhichfeelssimilartousingSQL'sgroupbyquerystyle,soitmayfeelmoreapproachablevs.usingMap-Reduce.Usingthegroupoperationsdoeshavesomelimitations,forexampleitisnotsupportedinasharededenvironmentanditreturnsthefullresultsetinasingleBSONobject,sotheresultshouldbesmall,lessthan10,000keys.
SpringprovidesintegrationwithMongoDB'sgroupoperationbyprovidingmethodsonMongoOperationstosimplifythecreationandexecutionofgroupoperations.ItcanconverttheresultsofthegroupoperationtoaPOJOandalsointegrateswithSpring'sResourceabstractionabstraction.ThiswillletyouplaceyourJavaScriptfilesonthefilesystem,classpath,httpserveroranyotherSpringResourceimplementationandthenreferencetheJavaScriptresourcesviaaneasyURIstylesyntax,e.g.'classpath:reduce.js;.ExternalizingJavaScriptcodeinfilesifoftenpreferabletoembeddingthemasJavastringsinyourcode.NotethatyoucanstillpassJavaScriptcodeasJavastringsifyouprefer.

5.8.1.ExampleUsage

Inordertounderstandhowgroupoperationsworkthefollowingexampleisused,whichissomewhatartifical.Foramorerealisticexampleconsultthebook'MongoDB-Thedefinitiveguide'.Acollectionnamed"group_test_collection"createdwiththefollowingrows.
{"_id":ObjectId("4ec1d25d41421e2015da64f1"),"x":1}
{"_id":ObjectId("4ec1d25d41421e2015da64f2"),"x":1}
{"_id":ObjectId("4ec1d25d41421e2015da64f3"),"x":2}
{"_id":ObjectId("4ec1d25d41421e2015da64f4"),"x":3}
{"_id":ObjectId("4ec1d25d41421e2015da64f5"),"x":3}
{"_id":ObjectId("4ec1d25d41421e2015da64f6"),"x":3}
Wewouldliketogroupbytheonlyfieldineachrow,the'x'fieldandaggregatethenumberoftimeseachspecificvalueof'x'occurs.Todothisweneedtocreateaninitialdocumentthatcontainsourcountvariableandalsoareducefunctionwhichwillincrementiteachtimeitisencountered.TheJavacodetoexecutethegroupoperationisshownbelow
GroupByResults<XObject>results=mongoTemplate.group("group_test_collection",
GroupBy.key("x").initialDocument("{count:0}").reduceFunction("function(doc,prev){prev.count+=1}"),
XObject.class);
Thefirstargumentisthenameofthecollectiontorunthegroupoperationover,thesecondisafluentAPIthatspecifiespropertiesofthegroupoperationviaaGroupByclass.InthisexampleweareusingjusttheintialDocumentandreduceFunctionmethods.Youcanalsospecifyakey-function,aswellasafinalizeraspartofthefluentAPI.Ifyouhavemultiplekeystogroupby,youcanpassinacommaseparatedlistofkeys.
TherawresultsofthegroupoperationisaJSONdocumentthatlookslikethis
{
"retval":[{"x":1.0,"count":2.0},
{"x":2.0,"count":1.0},
{"x":3.0,"count":3.0}],
"count":6.0,
"keys":3,
"ok":1.0
}
Thedocumentunderthe"retval"fieldismappedontothethirdargumentinthegroupmethod,inthiscaseXObjectwhichisshownbelow.
publicclassXObject{

privatefloatx;

privatefloatcount;

publicfloatgetX(){
returnx;
}

publicvoidsetX(floatx){
this.x=x;
}

publicfloatgetCount(){
returncount;
}

publicvoidsetCount(floatcount){
this.count=count;
}

@Override
publicStringtoString(){
return"XObject[x="+x+"count="+count+"]";
}
}
YoucanalsoobtaintharawresultasaDbObjectbycallingthemethodgetRawResultsontheGroupByResultsclass.
ThereisanadditionalmethodoverloadofthegroupmethodonMongoOperationswhichletsyouspecifyaCriteriaobjectforselectingasubsetoftherows.AnexamplewhichusesaCriteriaobject,withsomesyntaxsugarusingstaticimports,aswellasreferencingakey-functionandreducefunctionjavascriptfilesviaaSpringResourcestringisshownbelow.
importstaticorg.springframework.data.mongodb.core.mapreduce.GroupBy.keyFunction;
importstaticorg.springframework.data.mongodb.core.query.Criteria.where;

GroupByResults<XObject>results=mongoTemplate.group(where("x").gt(0),
"group_test_collection",
keyFunction("classpath:keyFunction.js").initialDocument("{count:0}").reduceFunction("classpath:groupReduce.js"),XObject.class);

5.9.Overridingdefaultmappingwithcustomconverters

InordertohavemorefinegrainedcontroloverthemappingprocessyoucanregisterSpringconverterswiththeMongoConverterimplementationssuchastheMappingMongoConverter.
TheMappingMongoConvertercheckstoseeifthereareanySpringconvertersthatcanhandleaspecificclassbeforeattemptingtomaptheobjectitself.To'hijack'thenormalmappingstrategiesoftheMappingMongoConverter,perhapsforincreasedperformanceorothercustommappingneeds,youfirstneedtocreateanimplementationoftheSpringConverterinterfaceandthenregisteritwiththeMappingConverter.


Note
FormoreinformationontheSpringtypeconversionserviceseethereferencedocshere.

5.9.1.SavingusingaregisteredSpringConverter

AnexampleimplementationoftheConverterthatconvertsfromaPersonobjecttoacom.mongodb.DBObjectisshownbelow
importorg.springframework.core.convert.converter.Converter;

importcom.mongodb.BasicDBObject;
importcom.mongodb.DBObject;

publicclassPersonWriteConverterimplementsConverter<Person,DBObject>{

publicDBObjectconvert(Personsource){
DBObjectdbo=newBasicDBObject();
dbo.put("_id",source.getId());
dbo.put("name",source.getFirstName());
dbo.put("age",source.getAge());
returndbo;
}
}

5.9.2.ReadingusingaSpringConverter

AnexampleimplementionofaConverterthatconvertsfromaDBObjectotaPersonobjectisshownnbelow
publicclassPersonReadConverterimplementsConverter<DBObject,Person>{

publicPersonconvert(DBObjectsource){
Personp=newPerson((ObjectId)source.get("_id"),(String)source.get("name"));
p.setAge((Integer)source.get("age"));
returnp;
}
}

5.9.3.RegisteringSpringConverterswiththeMongoConverter

TheMongoSpringnamespaceprovidesaconveniencewaytoregisterSpringConverterswiththeMappingMongoConverter.TheconfigurationsnippetbelowshowshowtomanuallyregisterconverterbeansaswellasconfiguringthewrappingMappingMongoConverterintoaMongoTemplate.
<mongo:db-factorydbname="database"/>

<mongo:mapping-converter>
<mongo:custom-converters>
<mongo:converterref="readConverter"/>
<mongo:converter>
<beanclass="org.springframework.data.mongodb.test.PersonWriteConverter"/>
</mongo:converter>
</mongo:custom-converters>
</mongo:mapping-converter>

<beanid="readConverter"class="org.springframework.data.mongodb.test.PersonReadConverter"/>

<beanid="mongoTemplate"class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-argname="mongoDbFactory"ref="mongoDbFactory"/>
<constructor-argname="mongoConverter"ref="mappingConverter"/>
</bean>
Youcanalsousethebase-packageattributeofthecustom-converterselementtoenableclasspathscanningforallConverterandGenericConverterimplementationsbelowthegivenpackage.
<mongo:mapping-converter>
<mongo:custom-convertersbase-package="com.acme.**.converters"/>
</mongo:mapping-converter>

5.9.4.Converterdisambiguation

GenerallyweinspecttheConverterimplementationsforthesourceandtargettypestheyconvertfromandto.DependingonwhetheroneofthoseisatypeMongoDBcanhandlenativelywewillregistertheconverterinstanceasreadingorwritingone.Havealookatthefollowingsamples:
//WriteconverterasonlythetargettypeisoneMongocanhandlenatively
classMyConverterimplementsConverter<Person,String>{…}

//ReadconverterasonlythesourcetypeisoneMongocanhandlenatively
classMyConverterimplementsConverter<String,Person>{…}
IncaseyouwriteaConverterwhosesourceandtargettypearenativeMongotypesthere'snowayforustodeterminewhetherweshouldconsideritasreadingorwritingconverter.Registeringtheconverterinstanceasbothmightleadtounwantedresultsthen.E.g.aConverter<String,Long>isambiguousalthoughitprobablydoesnotmakesensetotrytoconvertallStringsintoLongswhenwriting.Tobegenerallyabletoforcetheinfrastructuretoregisteraconverterforonewayonlyweprovide@ReadingConverteraswellas@WritingConvertertobeusedattheconverterimplementation.

5.10.IndexandCollectionmanagment

MongoTemplateprovidesafewmethodsformanagingindexesandcollections.ThesearecollectedintoahelperinterfacecalledIndexOperations.YouaccesstheseoperationsbycalilngthemethodindexOpsandpassineitherthecollectionnameorthejava.lang.Classofyourentity(thecollectionnamewillbederivedfromthe.classeitherbynameorviaannotationmetadata).
TheIndexOperationsinterfaceisshownbelow
publicinterfaceIndexOperations{

voidensureIndex(IndexDefinitionindexDefinition);

voiddropIndex(Stringname);

voiddropAllIndexes();

voidresetIndexCache();

List<IndexInfo>getIndexInfo();
}

5.10.1.MethodsforcreatinganIndex

Wecancreateanindexonacollectiontoimprovequeryperformance.

Example5.12.CreatinganindexusingtheMongoTemplate

mongoTemplate.indexOps(Person.class).ensureIndex(newIndex().on("name",Order.ASCENDING));

ensureIndexEnsurethatanindexfortheprovidedIndexDefinitionexistsforthecollection.

YoucancreatebothstandardindexesandgeospatialindexesusingtheclassesIndexDefinitionandGeoSpatialIndexrespectfully.Forexample,giventheVenueclassdefinedinaprevioussection,youwoulddeclareageospatialqueryasshownbelow
mongoTemplate.indexOps(Venue.class).ensureIndex(newGeospatialIndex("location"));

5.10.2.Accessingindexinformation

TheIndexOperationsinterfacehasthemethodgetIndexInfothatreturnsalistofIndexInfoobjects.Thiscontainsalltheindexesdefinedonthecollectcion.HereisanexamplethatdefinesanindexonthePersonclassthathasageproperty.
template.indexOps(Person.class).ensureIndex(newIndex().on("age",Order.DESCENDING).unique(Duplicates.DROP));

List<IndexInfo>indexInfoList=template.indexOps(Person.class).getIndexInfo();

//Contains
//[IndexInfo[fieldSpec={_id=ASCENDING},name=_id_,unique=false,dropDuplicates=false,sparse=false],
//IndexInfo[fieldSpec={age=DESCENDING},name=age_-1,unique=true,dropDuplicates=true,sparse=false]]

5.10.3.MethodsforworkingwithaCollection

It'stimetolookatsomecodeexamplesshowinghowtousetheMongoTemplate.Firstwelookatcreatingourfirstcollection.

Example5.13.WorkingwithcollectionsusingtheMongoTemplate

DBCollectioncollection=null;
if(!mongoTemplate.getCollectionNames().contains("MyNewCollection")){
collection=mongoTemplate.createCollection("MyNewCollection");
}

mongoTemplate.dropCollection("MyNewCollection");

getCollectionNamesReturnsasetofcollectionnames.

collectionExistsChecktoseeifacollectionwithagivennameexists.

createCollectionCreateanuncappedcollection

dropCollectionDropthecollection

getCollectionGetacollectionbyname,creatingitifitdoesn'texist.

5.11.ExecutingCommands

YoucanalsogetattheMongoDBdriver'sDB.command()methodusingtheexecuteCommand(…)methodsonMongoTemplate.ThesewillalsoperformexceptiontranslationintoSpring'sDataAccessExceptionhierarchy.

5.11.1.Methodsforexecutingcommands

CommandResultexecuteCommand(DBObjectcommand)ExecuteaMongoDBcommand.

CommandResultexecuteCommand(StringjsonCommand)ExecutetheaMongoDBcommandexpressedasaJSONstring.

5.12.LifecycleEvents

BuiltintotheMongoDBmappingframeworkareseveralorg.springframework.context.ApplicationEventeventsthatyourapplicationcanrespondtobyregisteringspecialbeansintheApplicationContext.BybeingbasedoffSpring'sApplicationContexteventinfastructurethisenablesotherproducts,suchasSpringIntegration,toeasilyreceivetheseeventsastheyareawellknowneventingmechanisminSpringbasedapplications.
Tointerceptanobjectbeforeitgoesthroughtheconversionprocess(whichturnsyourdomainobjectintoacom.mongodb.DBObject),you'dregisterasubclassofAbstractMongoEventListenerthatoverridestheonBeforeConvertmethod.Whentheeventisdispatched,yourlistenerwillbecalledandpassedthedomainobjectbeforeitgoesintotheconverter.

Example5.14.

publicclassBeforeConvertListenerextendsAbstractMongoEventListener<Person>{
@Override
publicvoidonBeforeConvert(Personp){
...doessomeauditingmanipulation,settimestamps,whatever...
}
}

Tointerceptanobjectbeforeitgoesintothedatabase,you'dregisterasubclassoforg.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListenerthatoverridestheonBeforeSavemethod.Whentheeventisdispatched,yourlistenerwillbecalledandpassedthedomainobjectandtheconvertedcom.mongodb.DBObject.

Example5.15.

publicclassBeforeSaveListenerextendsAbstractMongoEventListener<Person>{
@Override
publicvoidonBeforeSave(Personp,DBObjectdbo){
…changevalues,deletethem,whatever…
}
}

SimplydeclaringthesebeansinyourSpringApplicationContextwillcausethemtobeinvokedwhenevertheeventisdispatched.
ThelistofcallbackmethodsthatarepresentinAbstractMappingEventListenerare

onBeforeConvert-calledinMongoTemplateinsert,insertListandsaveoperationsbeforetheobjectisconvertedtoaDBObjectusingaMongoConveter.

onBeforeSave-calledinMongoTemplateinsert,insertListandsaveoperationsbeforeinserting/savingtheDBObjectinthedatabase.

onAfterSave-calledinMongoTemplateinsert,insertListandsaveoperationsafterinserting/savingtheDBObjectinthedatabase.

onAfterLoad-calledinMongoTempnlatefind,findAndRemove,findOneandgetCollectionmethodsaftertheDBObjectisretrievedfromthedatabase.

onAfterConvert-calledinMongoTempnlatefind,findAndRemove,findOneandgetCollectionmethodsaftertheDBObjectretrievedfromthedatabasewasconvertedtoaPOJO.

5.13.ExceptionTranslation

TheSpringframeworkprovidesexceptiontranslationforawidevarietyofdatabaseandmappingtechnologies.ThishastraditionallybeenforJDBCandJPA.TheSpringsupportforMongoDBextendsthisfeaturetotheMongoDBDatabasebyprovidinganimplementationoftheorg.springframework.dao.support.PersistenceExceptionTranslatorinterface.
ThemotivationbehindmappingtoSpring'sconsistentdataaccessexceptionhierarchyisthatyouarethenabletowriteportableanddescriptiveexceptionhandlingcodewithoutresortingtocodingagainstMongoDBerrorcodes.AllofSpring'sdataaccessexceptionsareinheritedfromtherootDataAccessExceptionclasssoyoucanbesurethatyouwillbeabletocatchalldatabaserelatedexceptionwithinasingletry-catchblock.Note,thatnotallexceptionsthrownbytheMongoDBdriverinheritfromtheMongoExceptionclass.Theinnerexceptionandmessagearepreservedsonoinformationislost.
SomeofthemappingsperformedbytheMongoExceptionTranslatorare:com.mongodb.NetworktoDataAccessResourceFailureExceptionandMongoExceptionerrorcodes1003,12001,12010,12011,12012toInvalidDataAccessApiUsageException.Lookintotheimplementationformoredetailsonthemapping.

5.14.Executioncallbacks

OnecommondesignfeatureofallSpringtemplateclassesisthatallfunctionalityisroutedintooneofthetemplatesexecutecallbackmethods.Thishelpsensurethatexceptionsandanyresourcemanagementthatmayberequiredareperformedconsistency.WhilethiswasofmuchgreaterneedinthecaseofJDBCandJMSthanwithMongoDB,itstilloffersasinglespotforexceptiontranslationandloggingtooccur.Assuch,usingthexeexecutecallbackisthepreferredwaytoaccesstheMongoDBdriver'sDBandDBCollectionobjectstoperformuncommonoperationsthatwerenotexposedasmethodsonMongoTemplate.
Hereisalistofexecutecallbackmethods.

<T>Texecute(Class<?>entityClass,CollectionCallback<T>action)ExecutesthegivenCollectionCallbackfortheentitycollectionofthespecifiedclass.

<T>Texecute(StringcollectionName,CollectionCallback<T>action)ExecutesthegivenCollectionCallbackonthecollectionofthegivenname.

<T>Texecute(DbCallback<T>action)ExecutesaDbCallbacktranslatinganyexceptionsasnecessary.

<T>Texecute(StringcollectionName,DbCallback<T>action)ExecutesaDbCallbackonthecollectionofthegivennametranslatinganyexceptionsasnecessary.

<T>TexecuteInSession(DbCallback<T>action)ExecutesthegivenDbCallbackwithinthesameconnectiontothedatabasesoastoensureconsistencyinawriteheavyenvironmentwhereyoumayreadthedatathatyouwrote.

HereisanexamplethatusestheCollectionCallbacktoreturninformationaboutanindex
booleanhasIndex=template.execute("geolocation",newCollectionCallbackBoolean>(){
publicBooleandoInCollection(Venue.class,DBCollectioncollection)throwsMongoException,DataAccessException{
List<DBObject>indexes=collection.getIndexInfo();
for(DBObjectdbo:indexes){
if("location_2d".equals(dbo.get("name"))){
returntrue;
}
}
returnfalse;
}
});

Chapter6.MongoDBrepositories

6.1.Introduction

ThischapterwillpointoutthespecialtiesforrepositorysupportforMongoDB.ThisbuildsonthecorerepositorysupportexplainedinChapter4,Repositories.Somakesureyou'vegotasoundunderstandingofthebasicconceptsexplainedthere.

6.2.Usage

ToaccessdomainentitiesstoredinaMongoDByoucanleverageoursophisticatedrepositorysupportthateasesimplementingthosequitesignificantly.Todoso,simplycreateaninterfaceforyourrepository:

Example6.1.SamplePersonentity

publicclassPerson{

@Id
privateStringid;
privateStringfirstname;
privateStringlastname;
privateAddressaddress;

//…gettersandsettersomitted
}

Wehaveaquitesimpledomainobjecthere.NotethatithasapropertynamedidoftypeObjectId.ThedefaultserializationmechanismusedinMongoTemplate(whichisbackingtherepositorysupport)regardspropertiesnamedidasdocumentid.CurrentlywesupportString,ObjectIdandBigIntegerasid-types.

Example6.2.BasicrepositoryinterfacetopersistPersonentities

publicinterfacePersonRepositoryextendsPagingAndSortingRepository<Person,Long>{

//additionalcustomfindermethodsgohere
}

Rightnowthisinterfacesimplyservestypingpurposesbutwewilladdadditionalmethodstoitlater.InyourSpringconfigurationsimplyadd

Example6.3.GeneralMongoDBrepositorySpringconfiguration

<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/data/mongohttp://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
<mongo:mongoid="mongo"/>

<beanid="mongoTemplate"class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-argref="mongo"/>
<constructor-argvalue="databaseName"/>
</bean>

<mongo:repositoriesbase-package="com.acme.*.repositories"/>

</beans>

ThisnamespaceelementwillcausethebasepackagestobescannedforinterfacesextendingMongoRepositoryandcreateSpringbeansforeachofthemfound.BydefaulttherepositorieswillgetaMongoTemplateSpringbeanwiredthatiscalledmongoTemplate,soyouonlyneedtoconfiguremongo-template-refexplicitlyifyoudeviatefromthisconvention.
AsourdomainrepositoryextendsPagingAndSortingRepositoryitprovidesyouwithCRUDoperationsaswellasmethodsforpaginatedandsortedaccesstotheentities.Workingwiththerepositoryinstanceisjustamatterofdependencyinjectingitintoaclient.SoaccessingthesecondpageofPersonsatapagesizeof10wouldsimplylooksomethinglikethis:

Example6.4.PagingaccesstoPersonentities

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
publicclassPersonRepositoryTests{

@AutowiredPersonRepositoryrepository;

@Test
publicvoidreadsFirstPageCorrectly(){

Page<Person>persons=repository.findAll(newPageRequest(0,10));
assertThat(persons.isFirstPage(),is(true));
}
}

ThesamplecreatesanapplicationcontextwithSpring'sunittestsupportwhichwillperformannotationbaseddependencyinjectionintotestcases.Insidethetestmethodwesimplyusetherepositorytoquerythedatastore.WehandtherepositoryaPageRequestinstancethatrequeststhefirstpageofpersonsatapagesizeof10.

6.3.Querymethods

MostofthedataaccessoperationsyouusuallytriggeronarepositoryresultaquerybeingexecutedagainsttheMongoDBdatabases.Definingsuchaqueryisjustamatterofdeclaringamethodontherepositoryinterface

Example6.5.PersonRepositorywithquerymethods

publicinterfacePersonRepositoryextendsPagingAndSortingRepository<Person,String>{

List<Person>findByLastname(Stringlastname);

Page<Person>findByFirstname(Stringfirstname,Pageablepageable);

PersonfindByShippingAddresses(Addressaddress);

}

Thefirstmethodshowsaqueryforallpeoplewiththegivenlastname.ThequerywillbederivedparsingthemethodnameforconstraintswhichcanbeconcatenatedwithAndandOr.Thusthemethodnamewillresultinaqueryexpressionof{"lastname":lastname}.Thesecondexampleshowshowpaginationisappliedtoaquery.JustequipyourmethodsignaturewithaPageableparameterandletthemethodreturnaPageinstanceandwewillautomaticallypagethequeryaccordingly.Thethirdexamplesshowsthatyoucanquerybasedonpropertieswhicharenotaprimitivetype.


Note
Notethatforversion1.0wecurrentlydon'tsupportreferringtoparametersthataremappedasDBRefinthedomainclass.
Table6.1.Supportedkeywordsforquerymethods

KeywordSampleLogicalresult
GreaterThanfindByAgeGreaterThan(intage){"age":{"$gt":age}}
LessThanfindByAgeLessThan(intage){"age":{"$lt":age}}
BetweenfindByAgeBetween(intfrom,intto){"age":{"$gt":from,"$lt":to}}
IsNotNull,NotNullfindByFirstnameNotNull(){"age":{"$ne":null}}
IsNull,NullfindByFirstnameNull(){"age":null}
LikefindByFirstnameLike(Stringname){"age":age}(ageasregex)
RegexfindByFirstnameRegex(Stringfirstname){"firstname":{"$regex":firstname}}
(Nokeyword)findByFirstname(Stringname){"age":name}
NotfindByFirstnameNot(Stringname){"age":{"$ne":name}}
NearfindByLocationNear(Pointpoint){"location":{"$near":[x,y]}}
WithinfindByLocationWithin(Circlecircle){"location":{"$within":{"$center":[[x,y],distance]}}}
WithinfindByLocationWithin(Boxbox){"location":{"$within":{"$box":[[x1,y1],x2,y2]}}}True
IsTrue,TruefindByActiveIsTrue(){"active":true}
IsFalse,FalsefindByActiveIsFalse(){"active":false}
ExistsfindByLocationExists(booleanexists){"location":{"$exists":exists}}

6.3.1.Geo-spatialrepositoryqueries

Asyou'vejustseenthereareafewkeywordstriggeringgeo-spatialoperationswithinaMongoDBquery.TheNearkeywordallowssomefurthermodification.Let'shavelookatsomeexamples:

Example6.6.AdvancedNearqueries

publicinterfacePersonRepositoryextendsMongoRepository<Person,String>

//{'location':{'$near':[point.x,point.y],'$maxDistance':distance}}
List<Person>findByLocationNear(Pointlocation,Distancedistance);
}

AddingaDistanceparametertothequerymethodallowsrestrictingresultstothosewithinthegivendistance.IftheDistancewassetupcontainingaMetricwewilltransparentlyuse$nearSphereinsteadof$code.

Example6.7.UsingDistancewithMetrics

Pointpoint=newPoint(43.7,48.8);
Distancedistance=newDistance(200,Metrics.KILOMETERS);
…=repository.findByLocationNear(point,distance);
//{'location':{'$nearSphere':[43.7,48.8],'$maxDistance':0.03135711885774796}}

AsyoucanseeusingaDistanceequippedwithaMetriccauses$nearSphereclausetobeaddedinsteadofaplain$near.BeyondthattheactualdistancegetscalculatedaccordingtotheMetricsused.

Geo-nearqueries

publicinterfacePersonRepositoryextendsMongoRepository<Person,String>

//{'geoNear':'location','near':[x,y]}
GeoResults<Person>findByLocationNear(Pointlocation);

//Nometric:{'geoNear':'person','near':[x,y],maxDistance:distance}
//Metric:{'geoNear':'person','near':[x,y],'maxDistance':distance,
//'distanceMultiplier':metric.multiplier,'spherical':true}
GeoResults<Person>findByLocationNear(Pointlocation,Distancedistance);

//{'geoNear':'location','near':[x,y]}
GeoResults<Person>findByLocationNear(Pointlocation);
}

6.3.2.MongoDBJSONbasedquerymethodsandfieldrestriction

Byaddingtheannotationorg.springframework.data.mongodb.repository.QueryrepositoryfindermethodsyoucanspecifyaMongoDBJSONquerystringtouseinsteadofhavingthequeryderivedfromthemethodname.Forexample
publicinterfacePersonRepositoryextendsMongoRepository<Person,String>

@Query("{'firstname':?0}")
List<Person>findByThePersonsFirstname(Stringfirstname);

}
Theplaceholder?0letsyousubstitutethevaluefromthemethodargumentsintotheJSONquerystring.
YoucanalsousethefilterpropertytorestrictthesetofpropertiesthatwillbemappedintotheJavaobject.Forexample,
publicinterfacePersonRepositoryextendsMongoRepository<Person,String>

@Query(value="{'firstname':?0}",fields="{'firstname':1,'lastname':1}")
List<Person>findByThePersonsFirstname(Stringfirstname);

}
Thiswillreturnonlythefirstname,lastnameandIdpropertiesofthePersonobjects.Theageproperty,ajava.lang.Integer,willnotbesetanditsvaluewillthereforebenull.

6.3.3.Type-safeQuerymethods

MongoDBrepositorysupportintegrateswiththeQueryDSLprojectwhichprovidesameanstoperformtype-safequeriesinJava.Toquotefromtheprojectdescription,"InsteadofwritingqueriesasinlinestringsorexternalizingthemintoXMLfilestheyareconstructedviaafluentAPI."Itprovidesthefollowingfeatures

CodecompletioninIDE(allproperties,methodsandoperationscanbeexpandedinyourfavoriteJavaIDE)

Almostnosyntacticallyinvalidqueriesallowed(type-safeonalllevels)

Domaintypesandpropertiescanbereferencedsafely(noStringsinvolved!)

Adoptsbettertorefactoringchangesindomaintypes

Incrementalquerydefinitioniseasier

PleaserefertotheQueryDSLdocumentationwhichdescribeshowtobootstrapyourenvironmentforAPTbasedcodegenerationusingMavenorusingAnt.
UsingQueryDSLyouwillbeabletowritequeriesasshownbelow
QPersonperson=newQPerson("person");
List<Person>result=repository.findAll(person.address.zipCode.eq("C0123"));

Page<Person>page=repository.findAll(person.lastname.contains("a"),
newPageRequest(0,2,Direction.ASC,"lastname"));
QPersonisaclassthatisgenerated(viatheJavaannotationpostprocessingtool)whichisaPredicatethatallowsyoutowritetypesafequeries.Noticethattherearenostringsinthequeryotherthanthevalue"C0123".
YoucanusethegeneratedPredicateclassviatheinterfaceQueryDslPredicateExecutorwhichisshownbelow
publicinterfaceQueryDslPredicateExecutor<T>{

TfindOne(Predicatepredicate);

List<T>findAll(Predicatepredicate);

List<T>findAll(Predicatepredicate,OrderSpecifier<?>...orders);

Page<T>findAll(Predicatepredicate,Pageablepageable);

Longcount(Predicatepredicate);
}
Tousethisinyourrepositoryimplementation,simplyinheritfromitinadditiiontootherrepositoryinterfaces.Thisisshownbelow
publicinterfacePersonRepositoryextendsMongoRepository<Person,String>,QueryDslPredicateExecutor<Person>{

//additionalfindermethodsgohere

}
WethinkyouwillfindthisanextremelypowerfultoolforwritingMongoDBqueries.

Chapter7.Mapping

RichmapingsupportisprovidedbytheMongoMappingConverter.MongoMappingConverterhasarichmetadatamodelthatprovidesafullfeaturesetoffunctionalitytomapdomainobjectstoMongoDBdocuments.Themappingmetadatamodelispopulatedusingannotationsonyourdomainobjects.However,theinfrastructureisnotlimitedtousingannotationsastheonlysourceofmetadatainformation.TheMongoMappingConverteralsoallowsyoutomapobjectstodocumentswithoutprovidinganyadditionalmetadata,byfollowingasetofconventions.
InthissectionwewilldescribethefeaturesoftheMongoMappingConverter.Howtouseconventionsformappingobjectstodocumentsandhowtooverridethoseconventionswithannotationbasedmappingmetadata.


Note
SimpleMongoConverterhasbeendeprecatedinSpringDataMongoDBM3asallofitsfunctionalityhasbeensubsumedintoMappingMongoConverter.

7.1.ConventionbasedMapping

MongoMappingConverterhasafewconventionsformappingobjectstodocumentswhennoadditionalmappingmetadataisprovided.Theconventionsare:

TheshortJavaclassnameismappedtothecollectionnameinthefollowingmanner.Theclass'com.bigbank.SavingsAccount'mapsto'savingsAccount'collectionname.

Allnestedobjectsarestoredasnestedobjectsinthedocumentand*not*asDBRefs

TheconverterwilluseanySpringConvertersregisteredwithittooverridethedefaultmappingofobjectpropertiestodocumentfield/values.

Thefieldsofanobjectareusedtoconverttoandfromfieldsinthedocument.PublicJavaBeanpropertiesarenotused.

Youcanhaveasinglenon-zeroargumentconstructorwhoseconstructorargumentnamesmatchtoplevelfieldnamesofdocument,thatconstructorwillbeused.Otherewisethezeroargconstructorwillbeused.ifthereismorethanonenon-zeroargumentconstructoranexceptionwillbethrown.

7.1.1.Howthe'_id'fieldishandledinthemappinglayer

MongoDBrequiresthatyouhavean'_id'fieldforalldocuments.Ifyoudon'tprovideonethedriverwillassignaObjectIdwithageneratedvalue.The"_id"fieldcanbeofanytypethe,otherthanarrays,solongasitisunique.ThedrivernaturallysupportsallprimitivetypesandDates.WhenusingtheMongoMappingConvertertherearecertainrulesthatgovernhowpropertiesfromtheJavaclassismappedtothis'_id'field.
Thefollowingoutlineswhatfieldwillbemappedtothe'_id'documentfield:

Afieldannotatedwith@Id(org.springframework.data.annotation.Id)willbemappedtothe'_id'field.

Afieldwithoutanannotationbutnamedidwillbemappedtothe'_id'field.

Thefollowingoutlineswhattypeconversion,ifany,willbedoneonthepropertymappedtothe_iddocumentfield.

Ifafieldnamed'id'isdeclaredasaStringorBigIntegerintheJavaclassitwillbeconvertedtoandstoredasanObjectIdifpossible.ObjectIdasafieldtypeisalsovalid.Ifyouspecifyavaluefor'id'inyourapplication,theconversiontoanObjectIdisdelectedtotheMongoDBdriver.Ifthespecified'id'valuecannotbeconvertedtoanObjectId,thenthevaluewillbestoredasisinthedocument's_idfield.

Ifafieldnamed'id'idfieldisnotdeclaredasaString,BigInteger,orObjectIDintheJavaclassthenyoushouldassignitavalueinyourapplicationsoitcanbestored'as-is'inthedocument's_idfield.

Ifnofieldnamed'id'ispresentintheJavaclassthenanimplicit'_id'filewillbegeneratedbythedriverbutnotmappedtoapropertyorfieldoftheJavaclass.

WhenqueryingandupdatingMongoTemplatewillusetheconvertertohandleconversionsoftheQueryandUpdateobjectsthatcorrespondtotheaboverulesforsavingdocumentssofieldnamesandtypesusedinyourquerieswillbeabletomatchwhatisinyourdomainclasses.

7.2.MappingConfiguration

Unlessexplicitlyconfigured,aninstanceofMongoMappingConverteriscreatedbydefaultwhencreatingaMongoTemplate.YoucancreateyourowninstanceoftheMappingMongoConvertersoastotellitwheretoscantheclasspathatstartupyourdomainclassesinordertoextractmetadataandconstructindexes.Also,bycreatingyourowninstanceyoucanregisterSpringconverterstouseformappingspecificclassestoandfromthedatabase.
YoucanconfiguretheMongoMappingConverteraswellascom.mongodb.MongoandMongoTemplateeitherusingJavaorXMLbasedmetadata.HereisanexampleusingSpring'sJavabasedconfiguration

Example7.1.@ConfigurationclasstoconfigureMongoDBmappingsupport

@Configuration
publicclassGeoSpatialAppConfigextendsAbstractMongoConfiguration{

@Bean
publicMongomongo()throwsException{
returnnewMongo("localhost");
}

@Override
publicStringgetDatabaseName(){
return"database";
}

@Override
publicStringgetMappingBasePackage(){
return"com.bigbank.domain";
}

//thefollowingareoptional

@Override
protectedvoidafterMappingMongoConverterCreation(MappingMongoConverterconverter){
Set<Converter<?,?>>converterList=newHashSet<Converter<?,?>>();
converterList.add(neworg.springframework.data.mongodb.test.PersonReadConverter());
converterList.add(neworg.springframework.data.mongodb.test.PersonWriteConverter());
converter.setCustomConverters(converterList);
}

@Bean
publicLoggingEventListener<MongoMappingEvent>mappingEventsListener(){
returnnewLoggingEventListener<MongoMappingEvent>();
}

}

AbstractMongoConfigurationrequiresyoutoimplementmethodsthatdefineacom.mongodb.Mongoaswellasprovideadatabasename.AbstractMongoConfigurationalsohasamethodyoucanoverridenamed'getMappingBasePackage'whichtellstheconverterwheretoscanforclassesannotatedwiththe@org.springframework.data.mongodb.core.mapping.Documentannotation.
YoucanaddadditionalconverterstotheconverterbyoverridingthemethodafterMappingMongoConverterCreation.AlsoshownintheaboveexampleisaLoggingEventListenerwhichlogsMongoMappingEventsthatarepostedontoSpring'sApplicationContextEventinfrastructure.


Note
AbstractMongoConfigurationwillcreateaMongoTemplateinstanceandregisteredwiththecontainerunderthename'mongoTemplate'.
YoucanalsooverridethemethodUserCredentialsgetUserCredentials()toprovidetheusernameandpasswordinformationtoconnecttothedatabase.
Spring'sMongoDBnamespaceenablesyoutoeasilyenablemappingfunctionalityinXML

Example7.2.XMLschematoconfigureMongoDBmappingsupport

<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="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/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/data/mongohttp://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!--Defaultbeannameis'mongo'-->
<mongo:mongohost="localhost"port="27017"/>

<mongo:db-factorydbname="database"mongo-ref="mongo"/>

<!--bydefaultlookforaMongoobjectnamed'mongo'-defaultnameusedfortheconverteris'mappingConverter'-->
<mongo:mapping-converterbase-package="com.bigbank.domain">
<mongo:custom-converters>
<mongo:converterref="readConverter"/>
<mongo:converter>
<beanclass="org.springframework.data.mongodb.test.PersonWriteConverter"/>
</mongo:converter>
</mongo:custom-converters>
</mongo:mapping-converter>

<beanid="readConverter"class="org.springframework.data.mongodb.test.PersonReadConverter"/>

<!--setthemappingconvertertobeusedbytheMongoTemplate-->
<beanid="mongoTemplate"class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-argname="mongoDbFactory"ref="mongoDbFactory"/>
<constructor-argname="mongoConverter"ref="mappingConverter"/>
</bean>

<beanclass="org.springframework.data.mongodb.core.mapping.event.LoggingEventListener"/>

</beans

Thebase-packagepropertytellsitwheretoscanforclassesannotatedwiththe@org.springframework.data.mongodb.core.mapping.Documentannotation.

7.3.MetadatabasedMapping

TotakefulladvantageoftheobjectmappingfunctionalityinsidetheSpringData/MongoDBsupport,youshouldannotateyourmappedobjectswiththe@org.springframework.data.mongodb.core.mapping.Documentannotation.Althoughitisnotnecessaryforthemappingframeworktohavethisannotation(yourPOJOswillbemappedcorrectly,evenwithoutanyannotations),itallowstheclasspathscannertofindandpre-processyourdomainobjectstoextractthenecessarymetadata.Ifyoudon'tusethisannotation,yourapplicationwilltakeaslightperformancehitthefirsttimeyoustoreadomainobjectbecausethemappingframeworkneedstobuildupitsinternalmetadatamodelsoitknowsaboutthepropertiesofyourdomainobjectandhowtopersistthem.

Example7.3.Exampledomainobject

packagecom.mycompany.domain;

@Document
publicclassPerson{

@Id
privateObjectIdid;

@Indexed
privateIntegerssn;

privateStringfirstName;

@Indexed
privateStringlastName;

}


Important
The@IdannotationtellsthemapperwhichpropertyyouwanttousefortheMongoDB_idpropertyandthe@IndexedannotationtellsthemappingframeworktocallensureIndexonthatpropertyofyourdocument,makingsearchesfaster.

7.3.1.Mappingannotationoverview

TheMappingMongoConvertercanusemetadatatodrivethemappingofobjectstodocuments.Anoverviewoftheannotationsisprovidedbelow

@Id-appliedatthefieldleveltomarkthefieldusedforidentiypurpose.

@Document-appliedattheclassleveltoindicatethisclassisacandidateformappingtothedatabase.Youcanspecifythenameofthecollectionwherethedatabasewillbestored.

@DBRef-appliedatthefieldtoindicateitistobestoredusingacom.mongodb.DBRef.

@Indexed-appliedatthefieldleveltodescribehowtoindexthefield.

@CompoundIndex-appliedatthetypeleveltodeclareCompoundIndexes

@GeoSpatialIndexed-appliedatthefieldleveltodescribehowtogeoindexthefield.

@Transient-bydefaultallprivatefieldsaremappedtothedocument,thisannotationexcludesthefieldwhereitisappliedfrombeingstoredinthedatabase

@PersistenceConstructor-marksagivenconstructor-evenapackageprotectedone-tousewheninstantiatingtheobjectfromthedatabase.ConstructorargumentsaremappedbynametothekeyvaluesintheretrievedDBObject.

@Value-thisannotationispartoftheSpringFramework.Withinthemappingframeworkitcanbeappliedtoconstructorarguments.ThisletsyouuseaSpringExpressionLanguagestatementtotransformakey'svalueretrievedinthedatabasebeforeitisusedtoconstructadomainobject.

@Field-appliedatthefieldlevelanddescribedthenameofthefieldasitwillberepresentedintheMongoDBBSONdocumentthusallowingthenametobedifferentthanthefieldnameoftheclass.

Themappingmetadatainfrastructureisdefinedinaseperatespring-data-commonsprojectthatistechnologyagnostic.SpecificsubclassesareusingintheMongoDBsupporttosupportannotationbasedmetadata.Otherstrategiesarealsopossibletoputinplaceifthereisdemand.
Hereisanexampleofamorecomplexmapping.
@Document
@CompoundIndexes({
@CompoundIndex(name="age_idx",def="{'lastName':1,'age':-1}")
})
publicclassPerson<TextendsAddress>{

@Id
privateStringid;

@Indexed(unique=true)
privateIntegerssn;

@Field("fName")
privateStringfirstName;

@Indexed
privateStringlastName;

privateIntegerage;

@Transient
privateIntegeraccountTotal;

@DBRef
privateList<Account>accounts;

privateTaddress;

publicPerson(Integerssn){
this.ssn=ssn;
}

@PersistenceConstructor
publicPerson(Integerssn,StringfirstName,StringlastName,Integerage,Taddress){
this.ssn=ssn;
this.firstName=firstName;
this.lastName=lastName;
this.age=age;
this.address=address;
}

publicStringgetId(){
returnid;
}

//nosetterforId.(getterisonlyexposedforsomeunittesting)

publicIntegergetSsn(){
returnssn;
}

//othergetters/settersommitted

7.3.2.CompoundIndexes

Compoundindexesarealsosupported.Theyaredefinedattheclasslevel,ratherthanonindidvidualproperties.


Note
Compoundindexesareveryimportanttoimprovetheperformanceofqueriesthatinvolvecriteriaonmultiplefields
Here'sanexamplethatcreatesacompoundindexoflastNameinascendingorderandageindescendingorder:

Example7.4.ExampleCompoundIndexUsage

packagecom.mycompany.domain;

@Document
@CompoundIndexes({
@CompoundIndex(name="age_idx",def="{'lastName':1,'age':-1}")
})
publicclassPerson{

@Id
privateObjectIdid;
privateIntegerage;
privateStringfirstName;
privateStringlastName;

}

7.3.3.UsingDBRefs

Themappingframeworkdoesn'thavetostorechildobjectsembeddedwithinthedocument.YoucanalsostorethemseparatelyanduseaDBReftorefertothatdocument.WhentheobjectisloadedfromMongoDB,thosereferenceswillbeeagerlyresolvedandyouwillgetbackamappedobjectthatlooksthesameasifithadbeenstoredembeddedwithinyourmasterdocument.
Here'sanexampleofusingaDBReftorefertoaspecificdocumentthatexistsindependentlyoftheobjectinwhichitisreferenced(bothclassesareshownin-lineforbrevity'ssake):

Example7.5.

@Document
publicclassAccount{

@Id
privateObjectIdid;
privateFloattotal;

}

@Document
publicclassPerson{

@Id
privateObjectIdid;
@Indexed
privateIntegerssn;
@DBRef
privateList<Account>accounts;

}

There'snoneedtousesomethinglike@OneToManybecausethemappingframeworkseesthatyou'rewantingaone-to-manyrelationshipbecausethereisaListofobjects.WhentheobjectisstoredinMongoDB,therewillbealistofDBRefsratherthantheAccountobjectsthemselves.


Important
Themappingframeworkdoesnothandlecascadingsaves.IfyouchangeanAccountobjectthatisreferencedbyaPersonobject,youmustsavetheAccountobjectseparately.CallingsaveonthePersonobjectwillnotautomaticallysavetheAccountobjectsinthepropertyaccounts.

7.3.4.MappingFrameworkEvents

Eventsarefiredthroughoutthelifecycleofthemappingprocess.ThisisdescribedintheLifecycleEventssection.
SimplydeclaringthesebeansinyourSpringApplicationContextwillcausethemtobeinvokedwhenevertheeventisdispatched.

7.3.5.OverridingMappingwithexplicitConverters

WhenstoringandqueryingyourobjectsitisconvenienttohaveaMongoConverterinstancehandlethemappingofallJavatypestoDBObjects.However,sometimesyoumaywanttheMongoConverter'sdomostoftheworkbutallowyoutoselectivlyhandletheconversionforaparticulartypeortooptimizeperformance.
Toselectivlyhandletheconversionyourself,registeroneormoreoneormoreorg.springframework.core.convert.converter.ConverterinstanceswiththeMongoConverter.


Note
Spring3.0introducedacore.convertpackagethatprovidesageneraltypeconversionsystem.ThisisdescribedindetailintheSpringreferencedocumentationsectionentitledSpring3TypeConversion.
ThesetConvertersmethodonSimpleMongoConverterandMappingMongoConvertershouldbeusedforthispurpose.ThemethodafterMappingMongoConverterCreationinAbstractMongoConfigurationcanbeoverridentoconfigureaMappingMongoConverter.TheexampleshereatthebeginingofthischaptershowhowtoperformtheconfigurationusingJavaandXML.
BelowisanexampleofaSpringConverterimplementationthatconvertsfromaDBObjecttoaPersonPOJO.
publicclassPersonReadConverterimplementsConverter<DBObject,Person>{

publicPersonconvert(DBObjectsource){
Personp=newPerson((ObjectId)source.get("_id"),(String)source.get("name"));
p.setAge((Integer)source.get("age"));
returnp;
}

}
HereisanexamplethatconvertsfromaPersontoaDBObject.
publicclassPersonWriteConverterimplementsConverter<Person,DBObject>{

publicDBObjectconvert(Personsource){
DBObjectdbo=newBasicDBObject();
dbo.put("_id",source.getId());
dbo.put("name",source.getFirstName());
dbo.put("age",source.getAge());
returndbo;
}

}

Chapter8.CrossStoresupport

Sometimesyouneedtostoredatainmultipledatastoresandthesedatastorescanbeofdifferenttypes.Onemightberelationalwhiletheotheradocumentstore.ForthisusecasewehavecreatedaseparatemoduleintheMongoDBsupportthathandleswhatwecallcross-storesupport.ThecurrentimplemenatationisbasedonJPAasthedriverfortherelationaldatabaseandweallowselectfieldsintheEntitiestobestoredinaMongodatabase.Inadditiontoallowingyoutostoreyourdataintwostoreswealsocoordinatepersistenceoperationsforthenon-transactionalMongoDBstorewiththetransactionlife-cyclefortherelationaldatabase.

8.1.CrossStoreConfiguration

AssumingthatyouhaveaworkingJPAapplicationandwouldliketoaddsomecross-storepersistenceforMongoDB.Whatdoyouhavetoaddtoyourconfiguration?
Firstofallyouneedtoaddadependencyonthespring-data-mongodb-cross-storemodule.UsingMaventhisisdonebyaddingadependencytoyourpom:

Example8.1.ExampleMavenpom.xmlwithspring-data-mongodb-cross-storedependency

<projectxmlns="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.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion>

...

<!--SpringData-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-cross-store</artifactId>
<version>${spring.data.mongo.version}</version>
</dependency>

...

</project>

OncethisisdoneweneedtoenableAspectJfortheproject.Thecross-storesupportisimplementedusingAspectJaspectssobyenablingcompiletimeAspectJsupportthecross-storefeatureswillbecomeavailabletoyourproject.InMavenyouwouldaddanadditionalplugintothe<build>sectionofthepom:

Example8.2.ExampleMavenpom.xmlwithAspectJpluginenabled

<projectxmlns="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.0http://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:YoumustuseMaven2.0.9oraboveortheseareignored(seeMNG-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,youneedtoconfigureyourprojecttouseMongoDBandalsoconfiguretheaspectsthatareused.ThefollowingXMLsnippetshouldbeaddedtoyourapplicationcontext:

Example8.3.ExampleapplicationcontextwithMongoDBandcross-storeaspectsupport

<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="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/mongohttp://www.springframework.org/schema/data/mongo/spring-mongo.xsdhttp://www.springframework.org/schema/jdbchttp://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/data/jpahttp://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">
...

<!--Mongoconfig-->
<mongo:mongohost="localhost"port="27017"/>

<beanid="mongoTemplate"class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-argname="mongo"ref="mongo"/>
<constructor-argname="databaseName"value="test"/>
<constructor-argname="defaultCollectionName"value="cross-store"/>
</bean>

<beanclass="org.springframework.data.mongodb.core.MongoExceptionTranslator"/>

<!--Mongocross-storeaspectconfig-->
<beanclass="org.springframework.data.persistence.document.mongo.MongoDocumentBacking"
factory-method="aspectOf">
<propertyname="changeSetPersister"ref="mongoChangeSetPersister"/>
</bean>
<beanid="mongoChangeSetPersister"
class="org.springframework.data.persistence.document.mongo.MongoChangeSetPersister">
<propertyname="mongoTemplate"ref="mongoTemplate"/>
<propertyname="entityManagerFactory"ref="entityManagerFactory"/>
</bean>

...

</beans>

8.2.WritingtheCrossStoreApplication

WeareassumingthatyouhaveaworkingJPAapplicationsowewillonlycovertheadditionalstepsneededtopersistpartofyourEntityinyourMongodatabase.Firstyouneedtoidentifythefieldyouwantpersited.ItshouldbeadomainclassandfollowthegeneralrulesfortheMongomappingsupportcoveredinpreviouschapters.ThefieldyouwantpersistedinMongoDBshouldbeannotatedusingthe@RelatedDocumentannotation.Thatisreallyallyouneedtodo!.Thecross-storeaspectstakecareoftherest.Thisincludesmarkingthefieldwith@Transientsoitwon'tbepersistedusingJPA,keepingtrackofanychangesmadetothefieldvalueandwritingthemtothedatabaseonsuccesfulltransactioncompletion,loadingthedocumentfromMongoDBthefirsttimethevalueisusedinyourapplication.HereisanexampleofasimpleEntitythathasafieldannotatedwith@RelatedEntity.

Example8.4.ExampleofEntitywith@RelatedDocument

@Entity
publicclassCustomer{

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
privateLongid;

privateStringfirstName;

privateStringlastName;

@RelatedDocument
privateSurveyInfosurveyInfo;

//gettersandsettersomitted

}

Example8.5.Exampleofdomainclasstobestoredasdocument

publicclassSurveyInfo{

privateMap<String,String>questionsAndAnswers;

publicSurveyInfo(){
this.questionsAndAnswers=newHashMap<String,String>();
}

publicSurveyInfo(Map<String,String>questionsAndAnswers){
this.questionsAndAnswers=questionsAndAnswers;
}

publicMap<String,String>getQuestionsAndAnswers(){
returnquestionsAndAnswers;
}

publicvoidsetQuestionsAndAnswers(Map<String,String>questionsAndAnswers){
this.questionsAndAnswers=questionsAndAnswers;
}

publicSurveyInfoaddQuestionAndAnswer(Stringquestion,Stringanswer){
this.questionsAndAnswers.put(question,answer);
returnthis;
}
}

OncetheSurveyInfohasbeensetontheCustomerobjectabovetheMongoTemplatethatwasconfiguredaboveisusedtosavetheSurveyInfoalongwithsomemetadataabouttheJPAEntityisstoredinaMongoDBcollectionnamedafterthefullyqualifiednameoftheJPAEntityclass.Thefollowingcode:

Example8.6.ExampleofcodeusingtheJPAEntityconfiguredforcross-storepersistence

Customercustomer=newCustomer();
customer.setFirstName("Sven");
customer.setLastName("Olafsen");
SurveyInfosurveyInfo=newSurveyInfo()
.addQuestionAndAnswer("age","22")
.addQuestionAndAnswer("married","Yes")
.addQuestionAndAnswer("citizenship","Norwegian");
customer.setSurveyInfo(surveyInfo);
customerRepository.save(customer);

ExecutingthecodeaboveresultsinthefollowingJSONdocumentstoredinMongoDB.

Example8.7.ExampleofJSONdocumentstoredinMongoDB

{"_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"}

Chapter9.Loggingsupport

AnappenderforLog4jisprovidedinthemavenmodule"spring-data-mongodb-log4j".Note,thereisnodependencyonotherSpringMongomodules,onlytheMongoDBdriver.

9.1.MongoDBLog4jConfiguration

Hereisanexampleconfiguration
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
TheimportantconfigurationtolookatasidefromhostandportisthedatabaseandcollectionPattern.Thevariablesyear,month,dayandhourareavailableforyoutouseinformingacollectionname.Thisistosupportthecommonconventionofgroupingloginformationinacollectionthatcorrespondstoaspecifictimeperiod,forexampleacollectionperday.
ThereisalsoanapplicationIdwhichisputintothestoredmessage.Thedocumentstoredfromloggingasthefollowingkeys:level,name,applicationId,timestamp,properties,traceback,andmessage.

Chapter10.JMXsupport

TheJMXsupportforMongoDBexposestheresultsofexecutingthe'serverStatus'commandontheadmindatabaseforasingleMongoDBserverinstance.ItalsoexposesanadministrativeMBean,MongoAdminwhichwillletyouperformadministrativeoperationssuchasdroporcreateadatabase.TheJMXfeaturesbuildupontheJMXfeaturesetavailableintheSpringFramework.Seehereformoredetails.

10.1.MongoDBJMXConfiguration

Spring'sMongonamespaceenablesyoutoeasilyenableJMXfunctionality

Example10.1.XMLschmeatoconfigureMongoDB

<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="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/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/data/mongohttp://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<beans>

<!--Defaultbeannameis'mongo'-->
<mongo:mongohost="localhost"port="27017"/>

<!--bydefaultlookforaMongoobjectnamed'mongo'-->
<mongo:jmx/>

<context:mbean-export/>

<!--TotranslateanyMongoExceptionsthrownin@Repositoryannotatedclasses-->
<context:annotation-config/>

<beanid="registry"class="org.springframework.remoting.rmi.RmiRegistryFactoryBean"p:port="1099"/>

<!--ExposeJMXoverRMI-->
<beanid="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>

ThiswillexposeseveralMBeans

AssertMetrics

BackgroundFlushingMetrics

BtreeIndexCounters

ConnectionMetrics

GlobalLoclMetrics

MemoryMetrics

OperationCounters

ServerInfo

MongoAdmin

ThisisshownbelowinascreenshotfromJConsole



PartIII.Appendix

AppendixA.Namespacereference

A.1.The<repositories/>element

The<repositories/>elementactsascontainerfor<repository/>elementsorcanbeleftemptytotriggerautodetection[1]ofrepositoryinstances.Attributesdefinedfor<repositories/>arepropagatedtocontained<repository/>elementsbutcanbeoverriddenofcourse.

TableA.1.Attributes

NameDescription
base-packageDefinesthepackagetobeusedtobescannedforrepositoryinterfacesextending*Repository(actualinterfaceisdeterminedbyspecificSpringDatamodule)inautodetectionmode.Allpackagesbelowtheconfiguredpackagewillbescanned,too.Inautoconfigurationmode(nonested<repository/>elements)wildcardsarealsoallowed.
repository-impl-postfixDefinesthepostfixtoautodetectcustomrepositoryimplementations.Classeswhosenamesendwiththeconfiguredpostfixwillbeconsideredascandidates.DefaultstoImpl.
query-lookup-strategyDeterminesthestrategytobeusedtocreatefinderqueries.SeeSection4.3.2.1,“Querylookupstrategies”fordetails.Defaultstocreate-if-not-found.

A.2.The<repository/>element

The<repository/>elementcancontainallattributesof<repositories/>exceptbase-package.Thiswillresultinoverridingthevaluesconfiguredinthesurrounding<repositories/>element.Thusherewewillonlydocumentextendedattributes.

TableA.2.Attributes

idDefinestheidofthebeantherepositoryinstancewillberegisteredunderaswellastherepositoryinterfacename.
custom-impl-refDefinesareferencetoacustomrepositoryimplementationbean.
[1]see???
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: