NoSQL Zone is brought to you in partnership with:

Amresh is a software designer/ developer based in New Delhi, India. He has worked with renowned software service providers. His area of interests are server side web development, NoSQL databases and Java programming. He loves reading, and sharing knowledge.


Instant Cassandra Query Language Amresh is a DZone MVB and is not an employee of DZone and has posted 8 posts at DZone. You can read more from them at their website. View Full User Profile

Working with MongoDB using Kundera

11.13.2012
| 4756 views |
  • submit to reddit

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.



Published at DZone with permission of Amresh Singh, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)