CRUD operations on MongoDB with Morphia
Java, Gradle, MongoDB, Morphia, Spring Boot
Introduction
In this post we are going to examine Morphia
as an Oject Document Mapper (ODM) tool for MongoDB
. We will map Java
Objects to MongoDB Documents. We will also perform basic Create, Read, Update and Delete (CRUD) with Morphia
.
To follow along this post, you should have a working installation of MongoDB on Windows
and / or Linux.
Prerequisites
Project Structure
This is a gradle
based project and we are using the standard Java project structure.
.
|__src/
| |__main/
| | |__java/
| | | |__com/
| | | | |juliuskrah/
| | | | |__morphia/
| | | | | |__Application.java
| | | | | |__config/
| | | | | | |__DataSourceConfig.java
| | | | | |__entity/
| | | | | | |__Author.java
| | | | | | |__Book.java
| | | | | |__repository/
| | | | | | |__AuthorRepository.java
| | | | | | |__BookRepository.java
| | | | | | |__impl/
| | | | | | | |__AuthorRepositoryImpl.java
| | | | | | | |__BookRepositoryImpl.java
| | |__resources/
| | | |__application.yaml
|__build.gradle
Project Dependencies
Before we can use Morphia
we need to add the dependency in our gradle buildscript.
file: build.gradle
To illustrate the use of Morphia
we will build a Spring-Boot
application.
file: build.gradle
Our full build.gradle
file:
Configure Spring Application
Let us start with setting up our Spring-Boot application
file: src/main/java/com/juliuskrah/morphia/Application.java
The above snippet starts up Spring-Boot with auto-configuration enabled.
Next we configure Morphia
for Spring-Boot.
file: src/main/java/com/juliuskrah/morphia/config/DataSourceConfig.java
Finally add the externalized configuration for the locally installed MongoDB database.
file: src\main\resources\application.yaml
Object Document Mapping
With all the basic requirements out of the way, we can start mapping our Java Objects to MongoDB documents using
an Author
to Book
example. An author can write many books, and a book can have multiple authors. We will keep
this simple by focusing on an author with many books and not the inverse relationship.
There are two ways that Morphia can handle your classes: as top level entities or embedded in others. Any class
annotated with @Entity
is treated as a top level document stored directly in a collection. Any class with @Entity
must have a field annotated with @Id
to define which field to use as the _id
value in the document written to
MongoDB. @Embedded
indicates that the class will result in a subdocument inside another document. @Embedded
classes
do not require the presence of an @Id
field. We would not cover @Embedded
in this post.
file: src/main/java/com/juliuskrah/morphia/entity/Book.java
file: src/main/java/com/juliuskrah/morphia/entity/Author.java
There are a few things here to discuss and others we will defer to later sections. The above classes are annotated using
the @Entity
annotation so we know that it will be a top level document. In the annotation, you’ll see "books"
and
"authors"
. By default, Morphia will use the class name as the collection name. If you pass a String instead, it will
use that value for the collection name. In this case, all Book
instances will be saved in to the books
collection
and all Author
instances to the authors
collection instead.
The @Indexes
annotation lists which indexes Morphia should create. In this instance, we’re defining an index named
name
on the field name
with the default ordering of ascending.
We have marked the id
field to be used as our primary key (the _id
field in the document). In this instance we are
using the Java driver type of ObjectId
as the ID type. The ID can be any type you would like but is generally
something like ObjectId
or Long
. There are two other annotations to cover but it should be pointed out now that
other than transient and static fields, Morphia will attempt to copy every field to a document bound for the database.
The simplest of the two remaining annotations is @Property
. This annotation is entirely optional. If you leave this
annotation off, Morphia will use the Java field name as the document field name. Often times this is fine. However,
some times you will want to change the document field name for any number of reasons. In those cases, you can use
@Property
and pass it the name to be used when this class is serialized out to a document to be handed off to MongoDB.
This just leaves @Reference
. This annotation is telling Morphia that this field refers to other Morphia mapped
entities. In this case Morphia will store what MongoDB calls a DBRef
which is just a
collection name and key value. These referenced entities must already be saved or at least have an ID assigned or
Morphia will throw an exception.
Creating the CRUD repository
We will create a simple repository class to take care of our CRUD operations.
file: src/main/java/com/juliuskrah/morphia/repository/impl/AuthorRepositoryImpl.java
file: src/main/java/com/juliuskrah/morphia/repository/impl/BookRepositoryImpl.java
Creating Documents
For the most part, you treat your Java objects just like you normally would. When you’re ready to write an object to the database, it’s as simple as this:
Reading Documents
Morphia attempts to make your queries as type safe as possible. All of the details of converting your data are handled by Morphia directly and only rarely do you need to take additional action. The following example illustrates this:
Updating Documents
There are two basic ways to update your data: insert/save a whole Entity or issue an update operation.
Updating (on the server)
The update method on Datastore
is used to issue a command to the server to change existing documents. The effects of
the update command are defined via UpdateOperations
methods:
Here we are updating the read
instance obtained from the database and updating the name
from Julius
to Pearl
.
The above executes the update in the database without having to pull in the document. The UpdateResults
instance
returned will contain various statistics about the update operation.
Updating (call create on an updated entity)
Updating data in MongoDB is as simple as updating your Java objects and then calling datastore.save()
with them
again:
Deleting Documents
After everything else, removes are really quite simple. Removing just needs a query to find and delete the documents
in question and then tell the Datastore
to delete them:
The full class will look something like this:
file: src/main/java/com/juliuskrah/morphia/Application.java
Conclusion
In this post we saw the basic mapping between a java object and a MongoDB document. We also saw how to perform basic
CRUD operations using Morphia
.
As usual you can find the full example to this guide in the github repository. Until the next post, keep doing cool things .