Spring Data Mongo: bridge MongoDB and Spring

#Spring Data Mongo: bridge MongoDB and Spring

MongoDB is one of the most popular NoSQL products, Spring Data Mongo(Maven archetype id is spring-data-mongodb) tries to provides a simple approach to access MongoDB.

##Configuration

Add the following code fragments in your Spring configuration.

<pre> &lt;!-- Mongo config --> &lt;mongo:db-factory id="mongoDbFactory" host="localhost" port="27017" dbname="conference-db" /> &lt;bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> &lt;constructor-arg ref="mongoDbFactory" /> &lt;/bean> &lt;mongo:repositories base-package="com.hantsylabs.example.spring.mongo" /> </pre>

Firstly, declare a DbFactory which is responsible for connecting to the MongoDB server.

Then, register the MongoTemplate object which envelop the data operations on MongoDB.

Lastly add mongo:repositories with an essential base-package attribute, Spring will discovery your defined Repositories in the packages.

Note: There is no transaction manager declared, Spring Data Mongo does not support Spring Transaction now.

Declare your Documents

Firstly, you have to create your domain classes. As comparison with the JPA concept, you can consider one row of records in a table is a Document in MongoDB, and a table which has many rows is a collection of Document.

<pre> @Document public class Conference { @Id private String id; @Version private Integer version; @NotNull private String name; @NotNull private String description; @NotNull @DateTimeFormat(style = "M-") private Date startedDate; @NotNull @DateTimeFormat(style = "M-") private Date endedDate; @NotNull private String slug; private Address address; //getters and setters. } public class Address { private String addressLine1; private String addressLine2; private String zipCode; private String city; private String country //getters and setters } @Document public class Signup { @Id private String id; @Version private Integer version; @DBRef private Conference conference; //other properites //getters and setters } </pre>

Conference and Signup are defined as @Document, and in Sginup, a @DBRef annotation is used to declare it is a reference of the Conference document. There is no JPA @OneToMany like annotations to define the relations between documents for MongoDB.

Address is annotated with nothing, and it is an embedded object in Conference document, in concept, it is very similar with the @Embedable class in JPA, and its lifecycle is fully controlled by its dependent Conference document.

In MongoDB, the data in the storage is presented as JSON like format.

The following is an example of Conference document.

<pre> { "_id" : ObjectId("51b422f066d41dc05f0292f0"), "_class" : "com.hantsylabs.example.spring.model.Conference", "version" : 0, "name" : "Test JUD", "description" : "JBoss User Developer Conference 2013 Boston", "startedDate" : ISODate("2013-07-09T06:38:40.272Z"), "endedDate" : ISODate("2013-07-16T06:38:40.272Z"), "slug" : "test-jud", "address" : { "addressLine1" : "address line 1", "addressLine2" : "address line 2", "zipCode" : "510000", "city" : "NY", "country" : "US" } } </pre>

The following is an example of Signup document.

<pre> { "_id" : ObjectId("51b422f066d41dc05f0292f1"), "_class" : "com.hantsylabs.example.spring.model.Signup", "version" : 0, "firstName" : "Hantsy", "lastName" : "Bai", "email" : "test@test.com", "phone" : "123 222 444", "occupation" : "Developer", "company" : "TestCompany", "comment" : "test comments", "createdDate" : ISODate("2013-06-09T06:38:40.288Z"), "status" : "PENDING", "conference" : DBRef("conference", ObjectId("51b422f066d41dc05f0292f0")) } </pre>

As you see, Address is embedded in the Conference document, and in Signup, there is a DBRef used to indicate it is a reference of Conference document.

@Id and @Version annotations are from the package org.springframework.data.annotation, which is similar with JPA, they are used to define the unique identification flag and version of a Document.

A String, BigInteger and Mongo specific ObjectId type property can be used as document id (annotated with the @Id annotation), Spring Data Mongo will convert it to Mongo internal id at runtime.

@Version is similar with the JPA specific @Version, Spring Data Mongo will fill this field automatically at runtime.

Spring Data Mongo also provides other annotations for the field mapping, such as @Field can be used to customize the filed name of a document in MongoDB, @Indexed is designated to create indies based on the fields at runtime.

##Query

Before you do some query operations, you have to create a Repository class as the steps in before post.

<pre> @Repository public interface ConferenceRepository extends MongoRepository&lt;Conference, String>{ } </pre>

MongoRepository is a Mongo specific Repository provided by Spring Data Mongo, it is dirven from PagingAndSortingRepository in Spring Data Commons.

Now you can use all the methods defined in the PagingAndSortingRepository and CrudRepository.

For example,

<pre> @Autowired ConferenceRepository conferenceRepository; conferenceRepository.save(); conferenceRepository.delete(); //etc </pre>

Firstly inject the ConferenceRepository in your classes, then use it as you expected.

The convention based methods are also supported by default in Spring Data Mongo, you have to research the Spring Data Mongo reference to get all available legal expression of the methods.

For example,

<pre> public Conference findBySlug(String slug); </pre>

It is used to find Conference by the slug property.

Custom Query

Like the Spring Data JPA, Spring Data Mongo also provides a @Query annotation(in the package org.springframework.data.mongodb.repository) to define and execute custom query.

For example,

<pre> @Query("{description:{ $regex: '*'+?0+'*', $options: 'i'}}") public List&lt;Conference> searchByDescriptionLike(String like); </pre>

The value attribute of the @Query annotation can accept a Mongo aggregation expression, please refer to the official document for the Aggregation.

You can also create a Custom interface and your implementation class to execute the custom query.

The steps are similar with ones in the Spring Data JPA post.

  1. Firstly create an interface make sure the class name is ended Custom.

<pre> public interface ConferenceRepositoryCustom { public List&lt;Conference> searchByDescription(String like); public void updateConferenceDescription(String description, String id ); } </pre>

  1. Modify the ConferenceRepository and add ConferenceRepositoryCustom interface to be extended.

<pre> @Repository public interface ConferenceRepository extends ConferenceRepositoryCustom, MongoRepository<Conference, String>{ } </pre>

  1. Create your imeplementation class to implement the methods deifned in ConferenceRepositoryCustom interface.

<pre> public class ConferenceRepositoryImpl implements ConferenceRepositoryCustom { private static final Logger log = LoggerFactory .getLogger(ConferenceRepositoryImpl.class); @Autowired MongoTemplate mongoTemplate; @Override public List&lt;Conference> searchByDescription(String d) { return mongoTemplate.find( Query.query(Criteria.where("description").regex( "[\\w]*" + d + "[\\w]*", "i")), Conference.class); } @Override public void updateConferenceDescription(String description, String id) { WriteResult result = mongoTemplate.updateMulti( Query.query(Criteria.where("id").is(id)), Update.update("description", description), Conference.class); log.debug("result @"+result.getField("description")); } } </pre>

Unlike the Spring Data JPA, there is no a Mongo SQL like language support in the Mongo Java Driver and Spring Data Mongo. In this implementation class, MongoTemplate is used to perform data operations.

Some other solutions I motioned before, such as DataNucleus provides standard JPA and JDO APIs for NoSQL, so using JPA APIs on Mongo is possible when use DataNucleus.

##MongoTemplate

MongoTemplate simplified the document collection based operations, please refer to the Mongo official document about Collection methods.

Criteria is a fluent API to build the query condition, it try to simplify the Mongo aggregation expression.

Query is used to combine the Criteria and other query condition, such as Pageable capability.

Update is the encapsulation of the Mongo core update operation, see Mongo core operations for more details.

In fact, you can use MongoTemplate freely in the classes outside of the Repository API.

<pre> @Repository public class AnyBean { @Autowired MongoTemplate mongoTemplate; } </pre>

And declare context:component-scan in your configuration to discover your beans.

<pre> &lt;context:component-scan base-package="com.hantsylabs.example.spring.mongo"> &lt;/context:component-scan> </pre>

QueryDSL integration

QueryDSL supports MongoDB officially, but the Metamodel generation and data operations is dependent on a third party project named Morphia which provides JPA like APIs for Mongo operations.

But unluckily, Spring did not adopt it in Spring Data Mongo project.

  1. Extend the Spring specific QueryDslPredicateExecutor, it is from Spring Data Commons, the same interface we used in before post.

<pre> @Repository public interface ConferenceRepository extends ConferenceRepositoryCustom, MongoRepository&lt;Conference, String>, QueryDslPredicateExecutor&lt;Conference> { } </pre>

  1. Generate the Metamodels.

Spring Data Mongo provides a custom APT processor to generate the Metamodels instead of the one provided in QueryDSL, it will scan the Spring specific @Document instead of the Morphia specific annotations.

<pre> &lt;plugin> &lt;groupId>com.mysema.maven&lt;/groupId> &lt;artifactId>apt-maven-plugin&lt;/artifactId> &lt;version>1.0.9&lt;/version> &lt;executions> &lt;execution> &lt;goals> &lt;goal>process&lt;/goal> &lt;/goals> &lt;configuration> &lt;outputDirectory>target/generated-sources/java&lt;/outputDirectory> &lt;processor>org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor&lt;/processor> &lt;/configuration> &lt;/execution> &lt;/executions> &lt;dependencies> &lt;dependency> &lt;groupId>com.mysema.querydsl&lt;/groupId> &lt;artifactId>querydsl-apt&lt;/artifactId> &lt;version>${querydsl.version}&lt;/version> &lt;/dependency> &lt;dependency> &lt;groupId>com.mysema.querydsl&lt;/groupId> &lt;artifactId>querydsl-mongodb&lt;/artifactId> &lt;classifier>apt&lt;/classifier> &lt;version>${querydsl.version}&lt;/version> &lt;/dependency> &lt;/dependencies> &lt;/plugin> </pre>

Run mvn compile to generate the Metamodels. Open the QConference class, you will find there is no difference from the early version generated for JPA entities in last post.

  1. Now you can use the APIs freely like the Spring Data JPA.

<pre> QConference qconf = QConference.conference; List&lt;Conference> conferences = (List&lt;Conference>) conferenceRepository .findAll(qconf.slug.eq("test-jud")); List&lt;Conference> conferences2 = (List&lt;Conference>) conferenceRepository .findAll(QConference.conference.address.country.eq("CN")); </pre>

All work as expected.

Try another one on Signup document collection.

<pre> List&lt;Signup> signups = (List&lt;Signup>) signupRepository .findAll(QSignup.signup.conference.eq(conf)); </pre>

Unfortunately, this query does not work as expected, you can find some issues have been filed about this problem on Spring JIRA. Currently, QueryDSL integration in Spring Data Mongo does not support reference(the fields marked with the @DBRef annotation) in query path. In this example, the conference caused the problem.

Spring Data Mongo also provides Geo, GridFS support abstraction which are not motioned here.

Summary

Spring Data Mongo provides simple data operations on MongoDB, due to there is no query language like JPQL for Mongo, all features provided in Spring Data Mongo based on the concept of Mongo client tools and shell interaction.

The most regrettable is it can not provide consistent experience as JPA support when adopting QueryDSL in projects.

转载于:https://my.oschina.net/hantsy/blog/136842

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值