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}









































5 Curious cases of Overloading & Generics

5 Curious cases of Overloading & Generics


If you are preparing for an Interview you can expect questions on  generics in java interview for sure , whether it is an position for Team lead or experience developer or Junior. But Generics gets more complicated when it mix with overloading in java. Let see the different scenarios when Generic mix with overloading.

What is generics in Java ?

Generics is technique which facilitates to declare a generic type(T, Irrespective of any Datatype in Java) in methods or class, which will be resolved later when caller of the method or class provide the actual Data Type(Integer, Boolean, String or ant Custom class) and ensure compile time safety but at the run-time it removes the type safety, we call this process as Type erasure.

Benefits of Generics:

By generics, we can achieve some level of the generic type declaration. To be specific Java is a static type language which means when we declare properties or methods we have to provide the type of the parameter or return type at the time of declaration.

But by generics we can defer the process we can declare methods or properties using generic syntax and later on caller can decide what data type pass to it, but remember it is not same as dynamic type language like javascript where var declaration means it represents any data types, on other hand Generics introduce the Type Inference from a bounded context, from Java perspective which is the first step towards functional programming(lambda) adaptation.

Challenges :

The most tricky part of generics is  by Type erasure, java removes the bounded type at runtime, so in java runtime generics and non-generics method/property declaration both are same no difference at all, to maintain backward compatibility  but generics ensure compile time safety so if you declare generics with certain type it only bounds to that certain type if you want to pass any other type compiler will complain instantly.

But as run time its type vanishes so in the case of Overloading we have to think what the method looks after type erasure erases the generic type, to do a perfect overloading unless compiler will complain.

In this Article, we will see 5 such scenarios which can occur often if I miss any please write in the comment section so I can add them to the Article.


Hope you are familiar with the generic syntax and how to use it.




Scenario 1 :

public Integer add(Integer a, Integer b) {
        System.out.println(a+b);
        return a+b;
    }

    /* (non-Javadoc)
    * @see com.example.generics.ICalculate#add(java.lang.Object, java.lang.Object)
    */

    public <T> T add(T a, T b) {
       
        Integer a1 = (Integer)a;
        Integer b1 = (Integer)b;
        Integer resut = a1+b1;
        System.out.println(" Result is" + resut);
        return (T) resut;
       
       
    }


See the two versions of add method can you tell me is it a valid overloading?

Yes this is a valid over loading as after type erasing public <T> T add(T a, T b) this method signature converts to , public Object  add(Object a, Object b) clearly it is different than
public Integer add(Integer a, Integer b) .



Scenario 2:

Now see the following version of overloading


public <T> T add(T a, T b) {
       
        Integer a1 = (Integer)a;
        Integer b1 = (Integer)b;
        Integer resut = a1+b1;
        System.out.println(" Result is" + resut);
        return (T) resut;
       
       
    }
   
   
   
public  Object add(Object a,Object b) {
       
        Integer a1 = (Integer)a;
        Integer b1 = (Integer)b;
        Integer resut = a1+b1;
        System.out.println(" Result is" + resut);
        return  resut;
       
       
    }



Can you tell me is it a valid overloading?

Probably you guess the answer it is not as I told you in previous example public <T> T add(T a, T b) this method signature converts to , public Object  add(Object a, Object b) after type erasing so now both signatures looks same so compiler will complain.


Scenario 3:

Now take the following version

public <T> T add(T a, T b) {
       
        Integer a1 = (Integer)a;
        Integer b1 = (Integer)b;
        Integer resut = a1+b1;
        System.out.println(" Result is" + resut);
        return (T) resut;
       
       
    }

public <T extends Number> T add(T a, T b) {
       
        Integer a1 = (Integer)a;
        Integer b1 = (Integer)b;
        Integer resut = a1+b1;
        System.out.println(" Result is" + resut);
        return (T) resut;
       
       
    }


Is the above a valid Overloading?

Yes it is a valid overloading as after type erasing  public <T> T add(T a, T b)  changed to public Object add(Object a,Object b) but public <T extends Number> T add(T a, T b)  changed to
public Number add(Number a, Number b) as T extends Number means any type which extends Number so after Type erasing it will take Number as infer type.


Exercise :

Can you tell me Is it valid overloading with explanation -- without paste that code in editor?
public Integer add(Integer a, Integer b) {
        System.out.println(a+b);
        return a+b;
    }


public <T extends Number> T add(T a, T b) {
       
    System.out.println(a.getClass().getName());
        Integer a1 = (Integer)a;
        Integer b1 = (Integer)b;
        Integer resut = a1+b1;
        System.out.println(" Result is" + resut);
        return (T) resut;
       
       
    }



Now let take a slightly different example where I try to pass a data type to a collection which will be the bounded context for that collection.

Scenario 4:

public void add(List<Integer> list) {
   
    System.out.println("add list of Integers");
   
   
}

public void add(List<?> list) {
   
    System.out.println("add/concat  list of any type");
   
   
}


Is it a valid overloading?

The Answer is, unfortunately, no, because after type erasing generics will lose its type and would become same as our old list.

So both signatures public void add(List<Integer> list)  and public void add(List<?> list) change to  public void add(List list)  and public void add(List list) so compiler will complain for sure.


Scenario 5 :


public void add(List<Integer> list) {
   
    System.out.println("add list of Integers");
   
   
}

public void add(List<Double> list) {
   
    System.out.println("add list of Integers");
   
   
}


As previous reason it is also not a perfect overloading.

So always pay attention of your generics signature while extending a class or overload method.