Working with MongoDB using Kundera


Kundera – a JPA 2.0 (Java Persistence API) based ORM library was originally developed for Cassandra database. A support for Hbase was later added to it.

Those who are new to Kundera, should read this to get a basic idea. For impatient ones – Get started with Kundera in 5 minutes!

Kundera now supports MongoDB – a document-oriented database. Some salient features of MongoDB datamodel are:

  1. Documents are stored as “collections” in DBs.
  2. A document can be embedded into other document, and hence no join is needed for retrieving data. This makes database operations fast.
  3. Drivers are available for most of the popular programming languages.

Our Data Model

In this tutorial, we’ll use below EMAIL and ATTCHMENT entities as our data model and perform CRUD operations using Kundera.
Data Model
Our entities in JSON notation:

{

EMAIL:
	{
	“MESSAGE_ID” : “1″,
	“SUBJECT” : “Please Join Meeting”,
	“BODY” : “Agenda: RFP discussion”,
	“FROM” :
		{
		“CONTACT_ID” : “a″,
		“FIRST_NAME” : “Amresh”,
		“LAST_NAME” : “Singh”,
		“EMAIL_ID” : “xamry@gmail.com”
		}
	“TO” :  [
                {
		“CONTACT_ID” : “b″,
		“FIRST_NAME” : “Vivek”,
		“LAST_NAME” : “Mishra”,
		“EMAIL_ID” : “mevivs@gmail.com”
		},
                {
		“CONTACT_ID” : “c″,
		“FIRST_NAME” : “Saurabh”,
		“LAST_NAME” : “Singh”,
		“EMAIL_ID” : “saurabh@gmail.com”
		}
                ]
	}
}
{
ATTACHMENT:
           {
           "ATTCHMENT_ID" : "aaa",
           "FILE_NAME" : "Agenda.doc",
           "FILE_TYPE" : "MS Word",
           "MESSAGE_ID" : "1"
           }
           {
           "ATTCHMENT_ID" : "bbb",
           "FILE_NAME" : "MOM_Last_Meeting.xls",
           "FILE_TYPE" : "MS Excel",
           "MESSAGE_ID" : "1"
           }
           {
           "ATTCHMENT_ID" : "ccc",
           "FILE_NAME" : "Client_Feedback.txt",
           "FILE_TYPE" : "Text",
           "MESSAGE_ID" : "1"
           }
}

Environment Setup

First, you need to install MongoDB on your machine. Follow this link to install and start MongoDB server on your machine.
Once done, Download Kundera  jars or include them into your maven project. Detailed steps are described here.

Create Entity Classes

  • Your entity classes should be annotated with @Entity and each fields should be annotated with @Column.
  • Field corresponding to primary key should be annotated with @Id.
  • In addition to this, your entity class should also be annotated with @Table, which is used by Kundera to determine the DB name and collection name.
  • All embedded entity fields should be annotated with @Embedded or @ElementCollection. They are stored with the enclosing entity table
  • All Relationships should be annotated with @OneToOne, @OneToMany, @ManyToOne or @ManyToMany. They are stored as separate collection and relationship is maintained via either Join Column or Join Table as the case may be.

Email Entity

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "EMAIL", schema = "KunderaExamples@twingo")
public class Email
{

 @Id
 @Column(name="MESSAGE_ID")
 private String messageId;

 @Column(name = "SUBJECT")
 private String subject;

 @Column(name = "BODY")
 private String body;

 @Embedded
 private Contact from;

 @ElementCollection
 @CollectionTable(name = "TO")
 private List<Contact> to;

 @OneToMany (cascade={CascadeType.ALL}, fetch=FetchType.LAZY)
 @JoinColumn(name="MESSAGE_ID")
 private List<Attachment> attachments;

 //Getters, setters, constructors and utility methods omitted.
}

Contact Embedded Object

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class Contact
{

 @Column(name = "CONTACT_ID")
 String contactId;

 @Column(name = "LAST_NAME")
 String lastName;

 @Column(name = "FIRST_NAME")
 String firstName;

 @Column(name = "EMAIL_ID")
 String emailId;

 //Getters, setters, constructors and utility methods omitted.
}

Attachment Entity

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "ATTACHMENT", schema = "KunderaExamples@twingo")
public class Attachment
{

 @Id
 @Column(name="ATTCHMENT_ID")
 private String attachmentId;

 @Column(name = "FILE_NAME")
 private String fileName;

 @Column(name = "FILE_TYPE")
 private String fileType;
 //Getters, setters, constructors and utility methods omitted.

}

Create persistence.xml

Add the below entry in your persistence.xml file for letting kundera know the persistence unit name and details. This name is used in the application code for making connection with MongoDB and persisting entities.

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="2.0">
<persistence-unit name="twingo">
    <provider>com.impetus.kundera.KunderaPersistence</provider>
    <properties>
        <property name="kundera.nodes" value="localhost" />
        <property name="kundera.port" value="27017" />
        <property name="kundera.keyspace" value="KunderaExamples" />
        <property name="kundera.dialect" value="mongodb" />
        <property name="kundera.client.lookup.class" value="com.impetus.client.mongodb.MongoDBClientFactory" />
        <property name="kundera.cache.provider.class" value="com.impetus.kundera.cache.ehcache.EhCacheProvider" />
        <property name="kundera.cache.config.resource" value="/ehcache-test.xml" />
    </properties>
 </persistence-unit>
</persistence>

Performing CRUD operations

We re now ready to write our simple java program for persisting, accessing and deleting “Email” entity.
For each of these operations, the steps to follow are:
  1. Create instance of EntityManagerFactory, providing Persistence Unit name as parameter.
  2. Perform database operation using JPA 2.0 API.
  3. Cleanup resources.

Insert a new entity:

Below is the code for writing Email entity into database which is stored as document into MongoDB.
 Email email = new Email();

 email.setMessageId("1");
 email.setSubject("Please Join Meeting");
 email.setBody("Agenda: RFP discussion");
 email.setFrom(new Contact("a", "Amresh", "Singh", "xamry@gmail.com"));

 email.addTo(new Contact("b", "Vivek", "Mishra", "mevivs@gmail.com"));
 email.addTo(new Contact("c", "Saurabh", "Singh", "saurabh@gmail.com"));

 email.addAttachment(new Attachment("aaa", "Agenda.doc", "MS Word"));
 email.addAttachment(new Attachment("bbb", "MOM_Last_Meeting.xls", "MS Excel"));
 email.addAttachment(new Attachment("ccc", "Client_Feedback.txt", "Text"));

 EntityManagerFactory emf = Persistence.createEntityManagerFactory("twingo");
 EntityManager em = emf.createEntityManager();
 em.persist(email);
 em.close();

 emf.close();

You can verify whether entity was successfully persisted from the mongodb shell:

amresh@ubuntu:/usr/local/mongodb$ ./bin/mongo
MongoDB shell version: 1.8.1
connecting to: test
> use KunderaExamples;
switched to db KunderaExamples
> show collections;
ATTACHMENT
EMAIL
system.indexes
> db.EMAIL.find();
{ "_id" : "1", "MESSAGE_ID" : "1", "subject" : { "SUBJECT" : "Please Join Meeting" }, "body" : { "BODY" : "Agenda: RFP discussion" }, "to" : [
 {
 "CONTACT_ID" : "b",
 "LAST_NAME" : "Mishra",
 "FIRST_NAME" : "Vivek",
 "EMAIL_ID" : "mevivs@gmail.com"
 },
 {
 "CONTACT_ID" : "c",
 "LAST_NAME" : "Singh",
 "FIRST_NAME" : "Saurabh",
 "EMAIL_ID" : "saurabh@gmail.com"
 }
], "from" : { "CONTACT_ID" : "a", "LAST_NAME" : "Singh", "FIRST_NAME" : "Amresh", "EMAIL_ID" : "xamry@gmail.com" } }

> db.ATTACHMENT.find();
{ "_id" : "aaa", "ATTCHMENT_ID" : "aaa", "FILE_NAME" : "Agenda.doc", "FILE_TYPE" : "MS Word", "MESSAGE_ID" : "1" }
{ "_id" : "bbb", "ATTCHMENT_ID" : "bbb", "FILE_NAME" : "MOM_Last_Meeting.xls", "FILE_TYPE" : "MS Excel", "MESSAGE_ID" : "1" }
{ "_id" : "ccc", "ATTCHMENT_ID" : "ccc", "FILE_NAME" : "Client_Feedback.txt", "FILE_TYPE" : "Text", "MESSAGE_ID" : "1" }
>

Update an existing entity:

Code for updating an entity is similar to the one used for inserting entity. You just need to set fields in the entity and persist it. It will be updated into MongoDB.

Find an entity:

Finding an entity means retrieving a single entity if you know the primary key. Here is the java code to accomplish this task:

 EntityManagerFactory emf = Persistence.createEntityManagerFactory("twingo");
 EntityManager em = emf.createEntityManager();
 Email email = em.find(Email.class, "1");
 em.close();
 emf.close();

Run a JPA Query:

Kundera supports JPA-QL. See below an example code that fetches all the emails from a collection.

 EntityManagerFactory emf = Persistence.createEntityManagerFactory("twingo");
 //Get all emails
 EntityManager em = emf.createEntityManager();
 Query q = em.createQuery("select e from Email e");
 List<?> emails = q.getResultList();
 em.close();
 emf.close();

Delete an Entity:

 EntityManagerFactory emf = Persistence.createEntityManagerFactory("twingo");
 EntityManager em = emf.createEntityManager();
 Email email = em.find(Email.class, "1");
 em.remove(email);
 em.close();
 emf.close();

Conclusion

Kundera makes it easier to work with NoSQL databases like Cassandra, Hbase, MongoDB by supporting JPA.  Programmers, as a result, need to write lesser lines of code, which is easy to understand and maintain. Another advantage is, you don’t need to rewrite your code in case you choose to change your database vendor (say, from MongoDB to Cassandra). The only thing you’ll require is to add a persistence unit entry into persistence.xml, and use that name into your application code.

About these ads

15 thoughts on “Working with MongoDB using Kundera

  1. im using jpa2-hibernate with Mysql. i want to migrate to MongoDB. do i need to downgrade my jpa to jpa1. and can you give us a pure kundera-jpa-spring tutorial, i mean no “com.impetus.kundera.loader.Configuration” stuff. i want to access the entityManager via persistanceContext, not with this “conf.getEntityManager()”.

  2. i’m using mongoDB in Spring MVC application and I wanna know if there is any annotation for relationship
    : one-to-one
    many-to-one
    one-to-many
    many-to-many

    i read in Spring data mongoDb document that

    “There’s no need to use something like @OneToMany because the mapping framework sees that you’re wanting a one-to-many relationship because there is a List of objects. When the object is stored in MongoDB, there will be a list of DBRefs rather than the Account objects themselves.

    so what for the other relationships?

    Tks in advance

  3. Although it’s possible to detect relationship type based on field data type as you said and as spring data does; Kundera, being a JPA based library, strictly uses these annotations for creating documents that are related. For embedding a document within another, use @Embedded or @ElementCollection annotation

  4. Very nice post!! Its useful…
    I´m using kundera-mongo with authentication, its work fine!
    I hope the criteria implementation.

  5. Pingback: Java ORMs for MongoDB | Tech Realm

  6. Hi Arvind,

    I am yet to try SpringData, so I won’t be able to compare these two. Kundera maybe better placed, if polyglot persistence is a key requirement. Simplicity and Java EE familiarity is another consideration area.

  7. Could you do another post on how to do native queries on MongoDB using Kundera?
    I found a bug on it that was closed and it looks like the code was changed to throw an exception that native queries aren’t supported in MongoDB ;-)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s