Learn Mongo with java8 : Part 1

Learn Mongodb with java 8


Welcome to my new tutorial series, learn MongoDB with Java 8.

Prerequisite  I hope that you have a basic idea about Bigdata & what are the new features offers in java8 because we use java8 extensively.

Objective: In this Article, we learn

  1. What is MongoDB?
  2. How to setup MongoDB?
  3. How to create a collection in MongoDB.
  4. Insert document in Collection
  5. Write a simple java program where we connect MongoDB and find a value from the collection we have created earlier.


Here is short & crisp details about Mongodb

MongoDB

MongoDB is a NoSQL database where we can store data as BSON format where, key represent the property and value represent, the property value stored against a key.

Document :  In Mongo, The Document represents a data structure which can hold any number of key and values. You can think Employee can be represented as a document where the name, address, age are the keys and their value as value stores in that document. Please note that document stores in binary JSON format generally we called it BSON(Binary JSON).


Example of a Document:

{ "_id" : { "$oid" : "58eb8c2b1de2b36bfcc74326"} , "name" : “Shamik Mitra”}

Collection :
In mongo generally same structured documents are logically put into a bucket, we called the same as the collection. You can think collection as a table in the relational database where every row represents a document. So we can say Employee collection holds Employee document. Note that this is logical, theoretically, a collection can contain any document, for example, a collection can contain Employee document as well as Car document no restrictions there.
NB: while designing, it is preferable to create a collection basis on same structure data.

No Schema :
This is the key difference between a SQL an NoSQL database although I don’t like those term it would be better to say relational and non-relational database. By NoSQL databases, it means it has no predefined schema it can hold anything in BSON format. To be specifically no data structure is defined so it is suitable for storing a Non Structured data.

It makes life easy to developer,  as in relational database there is a fixed schema,
If an Employee table contains the name, age, address column  It stores all data in the same format if we want to add gender we need to change the schema all together to fit new property but in Mongo, there are no such restrictions so it is schema free we can able to put any Employee with any properties.

NB: Although MongoDB is schema free but while designing we logically divide document based on collection so it maintaining an implicit schema!!!



Horizontal Scaling:

The success of Big Data lies in Horizontal scaling as Mongo is a part of Big Data stack,  it supports the same, By Horizontal Scaling MongoDB can distribute the data to multiple nodes, here each node represent a commodity machine i.e a low-cost computer, and we can add and remove node easily. So when we need to store more data we can add new nodes without impacting architecture, wherein Vertical scaling we need a super-computer and data reside in a single centralized source.
NB: Please note that by distributing data in multiple nodes mongo make itself fault tolerant but in Vertical scaling, as data reside in one centralized source if that goes down we lose out data so it is considered as the Single point of failure.



Sharding :

Sharding is a technique by which mongo breaks a gigantic data to small chunks, create a replica of each chunk and distribute those chunk into multiple nodes, when it is time to fetching Mongo holds a metadata information which tells mongo in which node data reside so it fetch contents from those nodes.





Mongo SetUp:


  1. Download the latest mongo Zip distribution from  following link


2. Create a directory D:\InstalledApps  and  Extract the zip in same location.

3. Rename distribution folder to mongodb.
4. Now create a folder named data inside mongodb folder
D:\InstalledApps\mongodb\data
5. Now open a command prompt and go to D:\InstalledApps\mongodb\bin folder using following command
cd D:\InstalledApps\mongodb\bin
6. Start mongodb server using following command
mongod.exe --dbpath D:\InstalledApps\mongodb\data

It will start the server in localhost:27017 port .

Set up Mongo Client :

We will use RoboMongo as our mongo client, it has a nice looking GUI and we can easily create collection add documents using RoboMongo.


Download Robomongo from here


Extract Zip file and click on RoboMongo.exe it will launch RoboMongo GUI

Connect Mongo server using server : localhost and port : 27017 which we started earlier.

Database
Now right click on Right-hand panel computer icon for Create a Database. Give test as a name of the database.



Collection : Now right click on Right hand panel collection icon under created database for create a collection . Create a collection named Employee.

Insert a Document : Now Right click on Employee collection and hit Insert Document and paste the following in text area

{ "name" : "Shamik" , "address" : "1 Nivedita Lane" , "age" : 32}

Hit save that will insert a document in Mongo Server.

Same thing you can achieve through Mongo console also.





Now we are all set for writing a java program to connect Mongodb using java.

Tools Used :
  1. Eclipse Neon
  2. Inbuilt Eclipse maven.
  3. Java 8

Step 1:

We will create a maven project in eclipse call mongoExample set java compiler as java 1.8, Please download java 1.8 if you do not have java 8.

Step 2:
Write a pom.xml like following

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.example</groupId>
 <artifactId>mongoExample</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <dependencies>
 <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongo-java-driver</artifactId>
        <version>2.10.1</version>
    </dependency>
 
 </dependencies>
</project>

Here we use mongo-java-driver to connect mongo Server using java.

Create a MongoContext:

Next part is to connect Mongo server using Java code so we will create a High-Level class which will abstract the logic of making the connection and also provides utility methods to fetch data from Mongo.

MongoContext.java

/**
*
*/
package com.example.config;

import java.net.UnknownHostException;
import java.util.function.Function;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.MongoClient;

/**
* @author Shamik Mitra
*
*/
public class MongoContext {
   
    private static MongoContext ctx = new MongoContext();
    private  MongoClient client;
    private  DB db;
   
    private MongoContext(){
       
        try{
            init();
        }catch(Exception ex){
            ex.printStackTrace();
        }
       
    }
   
    private void init() throws UnknownHostException{
        this.client = new MongoClient("localhost" , 27017);
    }
   
    public static MongoContext get(){
        return ctx;
    }
   
    public MongoContext connectDb(String dbname){
        if(db !=null){
            throw new RuntimeException("Already conected to " + db.getName() + "can't connect " + dbname);
        }
        this.db = client.getDB(dbname);
        System.out.println("DB Details :: " + db.getName());
        return ctx;
    }
   
    public <T,X> DBCursor findByKey(String collectionName,String key,T value,Function<T,X> convertDataType){
        DBCollection collection = db.getCollection(collectionName);
        BasicDBObject searchQuery = new BasicDBObject();
        searchQuery.put(key, convertDataType.apply(value));
        System.out.println("search Query ::" + searchQuery);
        DBCursor cursor = collection.find(searchQuery);
        return cursor;
    }

}


Explanation of the code :

Here I create a Singleton MongoContext Object, which connects to MongoDB server using mongo java drivers MongoClient class in init method.

this.client = new MongoClient("localhost" , 27017);

Now, we return that Context by the get() method.

At this point, we established a connection with Mongo server.

Next thing is to connect to the test database which we created earlier so I have created a generic method called connectDb(String dbName), Client will pass the database name it wants to connect. Please note that return type of this method is MongoContext itself, here I use Fluent API technique. If you want to know more about Fluent API  go here,


After that ,we want to do a query to fetch any documents from Mongo database.

So I create a Generic method,

public <T,X> DBCursor findByKey(String collectionName,String key,T value,Function<T,X> convertDataType)


This method takes four parameters

collectionName : It takes the collection name from where we want to fetch the document, here Employee is the target collection. You can be thought it as a table name.



Key : Key is the property by which we want to search the collection to fetch multiple documents in a collection, you can think it is the column name in a table which we put in where clause.

Value : It represents the value you search for it is same as the value provided in where clause against a column name.

Function<T,X>  : Here I define a Functional Interface which takes one data type and change it to another datatype T -> X, I need this because when I try to write a generic method findbyKey

I don’t know what will be the datatype of a key beforehand like in Employee collection name is String but age is Integer so If I want to search by name value will be String if age value will be Integer, so I need some strategy which converts the String value to desired Data Type by lambda Expression.

Find the following post for detailed understanding what is lambda Expression.


In that method body, I try to get the collection then create a SearchQuery using BasicDataObject then put key and value in that query.
At last we pass above query to the collection and get the result in a DBCursor Object which internally holds the result.

Time to Test

Create class called Main.java

/**
*
*/
package com.example.mongotest;

import com.example.config.MongoContext;
import com.mongodb.DBCursor;

/**
* @author Shamik Mitra
*
*/
public class Main {
    /**
    *
    */
    public static void main(String[] args) {
        DBCursor result = MongoContext.get().connectDb("test").findByKey("Employee", "age", 32,
                (value) -> new Integer(value));
        while (result.hasNext()) {
            System.out.println(result.next());
        }
    }
}


Here I get the MongoContext then connect the test DB and call the findByKey method by passing Employee as collection age as key and value as 32 and using lambda expression we tell that consider the datatype as Integer.

Please note that in findByKey,  I took data type of value as T,

So, you may be amazed why I pass a Functional Interface?
I can simply pass T data type to the query but I use functional interface to keep provision for any validation or sanity test of the value provided by the user before passing it to query.

Output :

DB Details :: test
search Query ::{ "age" : 32}
{ "_id" : { "$oid" : "58ecde108b308657b44937b1"} , "name" : "Shamik" , "adress" : "1 Nivedita Lane" , "age" : 32}