Monday, April 29, 2024
No menu items!
HomeDatabase ManagementAccelerate application development with Morphia ODM and Amazon DocumentDB

Accelerate application development with Morphia ODM and Amazon DocumentDB

Morphia’s object document mapping capabilities provide Amazon DocumentDB (with MongoDB compatibility) developers massive productivity gains, faster application development, and cleaner code bases by drastically reducing the boilerplate and complexity typically associated with persistent data access. Morphia takes care of bidirectional Java object and Amazon DocumentDB document mapping, automating transparent persistence operations. This enables developers to interact directly with familiar Java constructs, avoiding the need to navigate JSON-based structures and query syntax. You can simply focus on your core domain logic and building your target applications rather than wrestling with the intricacies of low-level Java driver APIs. The result is saved time, reduced lines of code, minimal invasive changes needed to existing object models, and increased agility to iterate on features.

Amazon DocumentDB is a scalable, highly durable, and fully managed database service for operating mission-critical JSON workloads for enterprises. Amazon DocumentDB simplifies your architecture by providing built-in security best practices, continuous backups, and native integrations with other AWS services. Morphia is an open source Object Document Mapper (ODM) for Java developers that provides a convenient way to map Java objects to Amazon DocumentDB documents.

In this post, we discuss how to develop an application using Morphia ODM with Amazon DocumentDB. Additionally, the integration steps highlight how Morphia streamlines working with Amazon DocumentDB behind the scenes through automated object document mapping.

Solution overview

Morphia is an ODM library built as a wrapper around Java drivers. ODM is a programming technique used to facilitate the interaction between object-oriented programming languages (like Java) and document-oriented databases (like Amazon DocumentDB and MongoDB), which store data in a flexible, schema-less manner. Morphia provides a way to map Java objects to Amazon DocumentDB documents and vice versa. This means that you can work with Amazon DocumentDB using Java objects and their corresponding methods, rather than directly dealing with low-level JSON queries and documents.

The following diagram illustrates the solution architecture.

Prerequisites

To complete this configuration, you need the following:

An Amazon DocumentDB cluster. You can integrate your Amazon DocumentDB cluster with a Java application using Morphia ODM libraries. If you don’t already have an Amazon DocumentDB cluster, see Get Started with Amazon DocumentDB to create a new cluster.
Java 17 installed.
Maven installed.

You may incur costs in your account related to Amazon DocumentDB. You can use the AWS Pricing Calculator to estimate the costs.

Create a Morphia Java project with Maven

From your AWS Cloud9 environment, launch a new terminal window by choosing Window and New Terminal. To generate a new template Java project, run the following command in the terminal window:

mvn archetype:generate -DgroupId=com.example.morphia.docdb -DartifactId=morphia-docdb-sample
-DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false

Alternatively, you can use the docdb-morphia-starter sample application from the GitHub repo.

Add Maven dependencies

You need to add Morphia to your project. You can download the pre-built JARs for Morphia from Maven Central and use them in your Java project.

You can also use a dependency management tool like Maven. Add the following to the dependencies section in your pom.xml file:

<dependency>
<groupId>dev.morphia.morphia</groupId>
<artifactId>morphia-core</artifactId>
<version>2.2.6</version>
</dependency>

Morphia is a wrapper around the MongoDB Java driver that depends on the Java driver. Add the following Java driver dependency to your pom.xml file:

<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.8.2</version>
</dependency>

Define your data model

Morphia uses models called entities that map to documents in a collection. It has a convenient annotation syntax that you can use to define those models and even create indexes.

To store and retrieve data from an Amazon DocumentDB database, let’s create a POJO model or entity class. This entity represents a collection in Amazon DocumentDB and uses annotations to define the collection name, attributes, keys, and indexes.

In this example, you create a products collection and a corresponding model object, which stores the details of products in a catalog database. You create a product model with six attributes: id, name, sku, description, inventory, and category.

Use the @Entity annotation to instruct Morphia that the following class will be used as an entity. By default, Morphia maps an entity to a collection in Amazon DocumentDB by the name of its class, but if you want to override this default name, you can add a name to @Entity annotation.

In the following example, we use @Entity(“products”) to specify the collection name as products.

You can specify the document’s primary key _id using the @Id annotation. If you don’t specify anything, Amazon DocumentDB generates an _id field while creating the document.

Other fields are left unannotated. By default, Morphia maps the fields in the Entity object to the attributes with the same name in an Amazon DocumentDB collection, but you can override this.

Inside the project’s directory, create a new file named Product.java within a package path matching com.example.morphia.docdb.entities. Copy the Java code from the sample project to this new file.

Connect with TLS enabled

To connect to a TLS-enabled Amazon DocumentDB cluster from a Java-based application, your program must use the AWS-provided certificate authority (CA) file to validate the connection. To use the Amazon Relational Database Service (Amazon RDS) CA certificate, refer to Connecting with TLS Enabled.

Configure the database and connection

To establish a connection to your Amazon DocumentDB cluster using Morphia libraries, you first need to retrieve your Amazon cluster endpoint. Complete the following steps:

On the Amazon DocumentDB console, in the navigation pane, choose Clusters.
Find your cluster and choose the Regional cluster identifier.
On the Connectivity & security tab, copy the command for connecting to your cluster with an application.
Remove &tlsCAFile=global-bundle.pem from the copied connection string. Note that you have already imported the AWS-provided CA file into the trust store.
Now you can create your connection.
Find the connection string for your Amazon DocumentDB cluster and add it as a constant in your App.java class. Then add the name of the database to use as a constant for the class. As a best practice, you can externalize these constants to an external configuration file.

static String docdb_uri = “mongodb://<user name>:<password>@<cluster end point>:<portnumber>/?tls=true&replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false”;
static String database_name = “catalog”;

With the connection string now configured, the next step is to set the keystore properties for establishing a secure connection.

Use the keystore in your application by setting the following system properties in your App.java class:

static String KEY_STORE_TYPE = “/tmp/certs/rds-truststore.jks”;
static String DEFAULT_KEY_STORE_PASSWORD = “<truststorePassword>”;
private static void setSslProperties() {
System.setProperty(“javax.net.ssl.trustStore”, KEY_STORE_TYPE);
System.setProperty(“javax.net.ssl.trustStorePassword”, DEFAULT_KEY_STORE_PASSWORD);
}

The connection string is now configured and the key store properties are set. You can now connect to the Amazon DocumentDB cluster using Morphia.

The following example demonstrates how to initialize a Morphia instance. You can then use this instance to configure entity mappings.

In your App.java class, add the following code to connect to the Amazon DocumentDB database. When you’re connected to the database, you can also configure the data store that you created.

public static void setUp() {
// set the keystore for establishing a secure connection
setSslProperties();
// A datastore instance for establishing a connection to Amazon DoocumentDB
datastore = Morphia.createDatastore(MongoClients.create(docdb_uri), database_name);
// Instruct Morphia, where to find your entity classes. Following line can be called multiple times with different packages or classes
datastore.getMapper().mapPackage(“com.example.morphia.docdb”);
datastore.ensureIndexes();
}

All the entities you defined within the com.example.morphia.docdb package in the previous step have now been mapped to documents in the collections.

Now that your entities are mapped to collections in the database, you can start interacting with the database.

Perform CRUD operations with Morphia

Let’s explore basic CRUD (Create, Read, Update, Delete) operations using the Morphia library and test each of these operations one by one.

Save or create

First, you can add a few documents to the collection using the save method. The save method takes a Product object as input and saves the product document in an Amazon DocumentDB collection. Add the following code snippet to your App.java class:

public static void saveProducts() {
datastore.save(new Product(“RayBan Sunglass Pro”, “1590234”,”RayBan Sunglasses for professional sports people”, 100, “fashion”));
datastore.save(new Product(“GUCCI Handbag”, “3451290”, “Fashion Hand bags for all ages”, 75, “fashion”));
datastore.save(new Product(“Round hat”, “8976045”, “”, 200, “fashion”));
datastore.save(new Product(“Polo shirt”, “6497023”, “Cool shirts for hot summer”, 25, “cloth”));
datastore.save(new Product(“Swim shorts”, “8245352”, “Designer swim shorts for athletes”, 200, “cloth”));
datastore.save(new Product(“Running shoes”, “3243662”, “Shoes for work out and trekking”, 20, “footware”));
}

Read

In this example, you perform two read operations. You fetch a product by name and find a list of products based on the category.

You will add two simple methods in the App.java class. The first method, findProductByName, queries the collection based on the name attribute. The second method, findAllProductsByCategory, retrieves all the documents of a particular category, as shown in the following code:

public static Product findProductByName (String name) {
System.out.println(” Getting product by name : ” + name);
Product product = datastore.find(Product.class).filter(
Filters.eq(“name”, name)).iterator(new FindOptions().limit(1))
.tryNext();
System.out.println(product);
return product;
}
public static List<Product> findAllProductsByCategory(String category) {
List<Product> productList = datastore.find(Product.class).filter(
Filters.eq(“category”, category)).iterator().toList();
System.out.println(productList);
return productList;
}

Update

You can update an existing document with the update or modify method on the Query instance. These update operations are run on the server without fetching any documents across the wire. Update operations are defined using a set of functions as defined on UpdateOperators. In this example, you query an existing product by SKU and increment the inventory by 10. Add the following method to your App.java class:

public static void updateInventory(String sku) {
System.out.println(” Updating Inventory for product by sku: ” + sku);
final Product updatedProduct = datastore.find(Product.class)
.filter(Filters.eq(“sku”, sku))
.modify(UpdateOperators.inc(“inventory”, 10))
.execute(new ModifyOptions().returnDocument(ReturnDocument.AFTER));
System.out.println(” Updated product: ” + updatedProduct);
}

Delete

In this example, you add two delete operations. First, delete one product by SKU. In the second method, you delete all documents (products) in the collection. Add the following methods to your App.java class:

public static void deleteProduct(String sku) {
datastore.find(Product.class)
.filter(Filters.eq(“sku”, sku))
.delete(new DeleteOptions().multi(true));
System.out.println(“Product with sku ” + sku + ” deleted”);
}
public static void deleteAll() {
datastore.find(Product.class)
.delete(new DeleteOptions().multi(true));
System.out.println(“All Products deleted.”);
}

Run and test your application

You can now invoke all the CRUD operations defined in the previous sections from within the main function in the App.java file. For the full implementation of the main function, refer to the completed App.java file in our sample project. This file contains the final, executable main method for running the application.

Run your Morphia-based sample application with the following Maven command:

mvn compile exec:java -Dexec.mainClass=”com.example.morphia.docdb.App” -Dexec.cleanupDaemonThreads=false

You’re done! You have successfully connected to Amazon DocumentDB using Morphia ODM libraries from a Java application.

Clean up

To avoid ongoing costs, complete the following steps to clean up your resources:

If you created a new Amazon DocumentDB cluster, delete the cluster.
If you used an existing Amazon DocumentDB cluster, run the following commands to delete the database and collections created by the sample application from the mongo shell:

use catalog db.dropDatabase();

If you created an AWS Cloud9 IDE, delete the environment.

Conclusion

In this post, you learned about using Morphia as an Object Document Mapper for Java applications that need to interface with Amazon DocumentDB. Specifically, you learned that Morphia provides a high-level abstraction layer that removes the need to use low-level Java driver APIs or write complex database access code. By using the Morphia libraries and following simple configuration steps to map Java objects to database documents, you can focus on your domain models and business logic rather than database plumbing.

You can find the example used in this post on GitHub. If you have feedback about this post, share it in the comments section.

About the authors

Gururaj S Bayari is a Senior DocumentDB Specialist Solutions Architect at AWS. He enjoys helping customers adopt Amazon’s purpose-built databases. He helps customers design, evaluate, and optimize their internet-scale and high-performance workloads powered by NoSQL or relational databases.

Anshu Vajpayee is a Senior DocumentDB Specialist Solutions Architect at AWS. He has been helping customers adopt NoSQL databases and modernize applications using Amazon DocumentDB. Before joining AWS, he worked extensively with relational and NoSQL databases for around 15 years.

Read MoreAWS Database Blog

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments