In this part of my blog series I’m going to show how easy it is to access a MongoDB datastore with Spring Data MongoDB.
MongoDB
MongoDB is a so called NoSQL datastore for document-oriented storage. A good place to start with MongoDB is the Developer Zone on the project’s homepage. After downloading and installing MongoDB we create a folder for data storage and start the server with
1${MONGO_HOME}/bin/mkdir ../data 2${MONGO_HOME}/bin/mongod --dbpath ../data --rest
and are welcomed by a web admin interface at http://localhost:28017/ . To play around with MongoDB, use the interactive mongo shell:
1C:\dev\bin\mongo\bin>mongo
2MongoDB shell version: 2.0.2
3connecting to: test
4> show dbs
5admin (empty)
6local (empty)
7test 0.078125GB
8> show collections
9foo
10system.indexes
11> db.foo.save({a:1, b:"bar"})
12> db.foo.save({a:1, b:"bar"})
13> db.foo.save({c:2, d:"doo"})
14> db.foo.find()
15{ "_id" : ObjectId("4f1e575efc25822cd8ff8cf2"), "a" : 1, "b" : "bar" }
16{ "_id" : ObjectId("4f1e5766fc25822cd8ff8cf3"), "a" : 1, "b" : "bar" }
17{ "_id" : ObjectId("4f1e5771fc25822cd8ff8cf4"), "c" : 2, "d" : "doo" }
We display the names of the databases, than the collections (a collection is a logical namespace) inside the default database test
. After that, we persists three documents in JSON notation. Doing so we observe:
- each document has a unique id
- there may be more than one document holding the same attribute set in the same collection
- documents with different structures can be stored in the same collection
So a collection is really not the same thing as a table of a relational database. We also have no support for ACID transaction handling. Welcome to the cloud!
Spring Data MongoDB
Spring Data MongoDB works basically the same way as Spring Data JPA : you define your custom repository finders by writing only interface methods and Spring provides an implementation at runtime. The basic CRUD operation are supported without the need to write a single line of code.
Configuration
First of all we let Maven download the latest realeae version of Spring Data MongoDB:
1<dependency> 2 <groupId>org.springframework.data</groupId> 3 <artifactId>spring-data-mongodb</artifactId> 4 <version>1.0.0.RELEASE</version> 5</dependency>
Using the mongo
namespace your Spring application context can be configured quite easy:
1<!-- Connection to MongoDB server --> 2<mongo:db-factory host="localhost" port="27017" dbname="test" /> 3<!-- MongoDB Template --> 4<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> 5 <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/> 6</bean> 7 8<!-- Package w/ automagic repositories --> 9<mongo:repositories base-package="mongodb"/>
The connection to our MongoDB server and the database to use are configured with the tag. For fine tuning of the connection (connection pooling, clustering etc.) use the elements
und
instead. Then we define a template that refers our DB factory. Finally we have to configure the package holding our repository interfaces (same as with Spring Data JPA). By default the only MongoDBTemplate inside the application context is used. If there are more than one template, you can specify which one to use with
.
Example
Similar to the blog post on Spring Data JPA we like to persist some simple User
objects:
1@Document
2public class User {
3
4 @Id
5 private String id;
6
7 @Indexed
8 private String fullName;
9
10 private Date lastLogin;
11 ...
The annotations are not required. But to define an index we have to use the @Indexed
annotation. To begin with we use a very simple repository …
1public interface UserRepository extends MongoRepository<User, String> {}
… to save our first documents:
1public class MongoDBRepoTest {
2
3 @Autowired UserRepository repo;
4
5 @Before public void setUp() {
6 repo.save(new User("root", "Superuser"));
7 for ( int i = 0; i < 6; i++ ) {
8 repo.save( new User( String.format("user%02d", i), "User " + i ) );
9 }
10 }
We use the mongo shell to check if our documents were persisted:
1MongoDB shell version: 1.8.3
2connecting to: test
3> db.user.find()
4{ "_id" : "user00", "_class" : "mongodb.User", "fullName" : "User 0", "lastLogin" : ISODate("2012-01-27T08:16:37.589Z") }
5{ "_id" : "user01", "_class" : "mongodb.User", "fullName" : "User 1", "lastLogin" : ISODate("2012-01-27T08:16:37.589Z") }
6{ "_id" : "user02", "_class" : "mongodb.User", "fullName" : "User 2", "lastLogin" : ISODate("2012-01-27T08:16:37.590Z") }
7{ "_id" : "user03", "_class" : "mongodb.User", "fullName" : "User 3", "lastLogin" : ISODate("2012-01-27T08:16:37.590Z") }
8{ "_id" : "user04", "_class" : "mongodb.User", "fullName" : "User 4", "lastLogin" : ISODate("2012-01-27T08:16:37.591Z") }
9{ "_id" : "user05", "_class" : "mongodb.User", "fullName" : "User 5", "lastLogin" : ISODate("2012-01-27T08:16:37.591Z") }
10{ "_id" : "root", "_class" : "mongodb.User", "fullName" : "Superuser", "lastLogin" : ISODate("2012-01-27T08:16:37.576Z") }
11> db.user.count()
127
13> db.user.getIndexes()
14[
15 {
16 "name" : "_id_",
17 "ns" : "test.user",
18 "key" : {
19 "_id" : 1
20 },
21 "v" : 0
22 },
23 {
24 "name" : "fullName",
25 "ns" : "test.user",
26 "dropDups" : false,
27 "sparse" : false,
28 "unique" : false,
29 "key" : {
30 "fullName" : 1
31 },
32 "v" : 0
33 }
34]
You may have noticed that a collection named user
was created on the fly. If you want a non-default collection name (the lowercase name of the Java class), use the document annotation: @Document(collection="...")
. The full qualified class name is persisted with the _class
attribute. There are two indexes now: the default index for the id attribute and the index generated from the class attribute fullName
with the @Indexed
annotation.
Now we write some more custom finders:
1public interface UserRepository extends MongoRepository<User, String> {
2 @Query("{ fullName: ?0 }")
3 List<User> findByTheUsersFullName(String fullName);
4
5 List<User> findByFullNameLike(String fullName, Sort sort);
6}
With the @Query
annotation you can define random queries in MongoDB syntax. The second query shows a finder that provides a search with regular expressions. When writing your first queries the comparison between MongoDB and SQL can be very helpful.
The complete source code of the example can be downloaded from Github .
MongoDBTemplate
Not all MongoDB features are exposed with the interface based repository approach. If you want to manage collections or use map/reduce , you have to use the API of the MongoDBTemplate
.
Summary
After a short introduction to MongoDB we were able to persist the first object very fast using Spring Data MongoDB. After that, we wrote custom finders with just a few lines of code.
A Spring application using Spring Data MongoDB as a persistence layer can be deployed to a cloud platform like CloudFoundry . This blog post show how easy that can be done.
What happened before?
Part 1: Spring Data Commons
Part 2: Spring Data JPA
What’s next?
Expect upcoming blog posts on Spring Data Neo4j and Spring GemFire .
More articles
fromTobias Trelle
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog author
Tobias Trelle
Software Architect
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.