Overview of Spring Data MongoDB


The Spring Data umbrella project aims at providing support for new data access technologies. It hosts many sub-projects and one of them is dedicated to MongoDB. Spring Data MongoDB comes with tons of features for the Java developers working with MongoDB: database and collection management, lightweight object-document mapping, and dynamic repositories are some of these features. Let's take a tour!

Working on DBObjects with the MongoTemplate

The MongoTemplate is easy to set up, it justs needs a Mongo instance (i.e. connection to MongoDB) and the name of the database to work with:

MongoOperations tpl = new MongoTemplate(new Mongo(),"spring-mongo");

Note we use the MongoOperations interface. Working against interfaces is a best practice and can make your life easier if you want to mock your Mongo template with JDK proxies.

The Mongo template provides methods to manipulate collections:

if(tpl.collectionExists("contact")) {
  tpl.dropCollection("contact");
}

It lets you also work with plain DBObject (the document interface in the MongoDB Java driver):

DBObject doc = BasicDBObjectBuilder.start()
  .add("firstname","Arnaud")
  .add("lastname","Cogoluègnes")
  .get();
tpl.getCollection("contact").insert(doc);
assertThat(tpl.getCollection("contact").count(),is(1L));

Neat, but nothing much new compared to the basic Java driver so far. This is where it comes to work with domain objects that the Mongo template really shines.

Object-Document mapping

Using a document datastore doesn't mean your application doesn't have a fixed, rich domain model. Working with a set a domain classes makes you more productive than strictly working with DBOjects, which are - let's face it - hard to manipulate.

Spring's MongoTemplate offers a powerful object-document mapping engine. Such a tool is convenient for validation, type checking, and associations.

Spring's object-document mapper is as simple as this to use:

Contact contact = new Contact("Arnaud","Cogoluègnes");
tpl.insert(contact);
assertThat(tpl.getCollection("contact").count(),is(1L));

The Mongo template stores the Contact object in a contact collection. If we use the Mongo shell to see the content of the collection:

> db.contact.find()
{ "_id" : ObjectId("4fa0e00f44ae8342620a0bc3"), 
   "_class" : "com.zenika.domain.Contact", 
   "firstname" : "Arnaud", 
   "lastname" : "Cogoluègnes" 
}

You don't need to provide any mapping metadata, but you can if you want to:

package com.zenika.domain;
 
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
 
@Document
public class Contact {
 
  @Id
  private String id;
 
  private String firstname,lastname;
 
  public Contact() {}
 
  (...)
}

Once there are documents in your collections, you usually want to retrieve them through some query API. Let's see what the Mongo template offers.

Query DSL

Spring Data MongoDB provides a fluent query API. The Mongo template has a find method that accepts a Query instance. Such a Query is usually created with static factory methods:

import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
(...)
List<Contact> contacts = tpl.find(query(where("firstname").is("Arnaud")),Contact.class);
assertThat(contacts.size(),is(1));

This query API supports all the MongoDB query features (operators like greater than, and, or, and so on, sort, and pagination as well).

The Mongo template has a great API you can use everywhere in your applications, but you can also choose to have a dedicated access layer. Spring Data MongoDB can also help by providing ready-to-use, dynamic repositories.

Dynamic repositories

A data access layer can be useful to abstract the underlying data access technology of an application. Upper layers - usually a business layer - don't know anything about this data access technology. Such an abstraction is useful if the application switches from one framework to another or if one mocks the data access layer to unit test the business layer more easily.

With Spring Data MongoDB, one can easily expose CRUD repositories. The first step is to declare a repository interface for an entity class:

package com.zenika.repo;
 
import org.springframework.data.mongodb.repository.MongoRepository;
import com.zenika.domain.Contact;
 
public interface ContactRepository extends MongoRepository<Contact, String> { }

The second step is to tell Spring Data MongoDB where to find your repository interfaces:

<mongo:repositories base-package="com.zenika.repo" />
 
<mongo:mongo />
 
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
  <constructor-arg ref="mongo" />
  <constructor-arg value="spring-mongo" />
</bean>

Note you need to provide the framework with a Mongo instance and a Mongo template. You don't need to provide any implementation for the repository: Spring Data MongoDB implements the behavior dynamically. You just have to look up the repo from the Spring context and use it:

ContactRepository contactRepository = context.getBean(ContactRepository.class);
contactRepository.deleteAll();
Contact contact = new Contact("Arnaud","Cogoluègnes");
contactRepository.save(contact);
assertThat(contactRepository.count(),is(1L));

By extending MongoRepository, the repository provides all the CRUD operations (with bonuses like sorting and paging). By following conventions, you can also provide your own methods, the repository will implements them on the fly:

public interface ContactRepository extends MongoRepository<Contact, String> {
 
  // declaring a new method
  List<Contact> findByFirstname(String firstname);
 
}
 
// using the new method, no need to implement it
List<Contact> contacts = contactRepository.findByFirstname("Arnaud");
assertThat(contacts.size(),is(1));

Thanks to the name of the method, Spring Data MongoDB understands the criteria is on the firstname property.

This dynamic repository support is sophisticated: one can "blend" its own implementation with the dynamic ones, add parameters for sorting or paging, provides JSON-based queries with annotations, and so on. Note Spring Data provides the exact same support for JPA.

Conclusion

The Spring Data MongoDB provides a comprehensive, yet progressive support for Java-based MongoDB applications. MongoDB's Java driver works great, but can frustrate people used to working with strongly-typed domain models.

We scratched only the surface of Spring Data MongoDB, don't hesitate to check its reference documentation for the JPA integration (polyglot persistence), the listener support (callbacks around the lifecycle of entities), or its geo-spatial integration. Check out also the brand-new Spring Data REST project if you want to expose your MongoDB documents as REST resources thanks to the dynamic repositories.

Source code


Fil des commentaires de ce billet

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.