Wednesday 22 May 2013

Java and MongoDB: Generic Service class in java for reading the collection from mongodb

Hello  Everyone, Let's create a service class(a very generic) in java which will accept all the required parameters for reading a collection from MongoDb and return JSON string as result.


Here is the quick guide to do this. Before we move to the actual code let me put an introductory note on NO SQL database. Starting with the NO SQL database, today it is one of the hot topic:  as name signifies, it is definitely not a relational data base, where we store the data in some  table formats and which grows in both the direction vertically as well Horizontally this become very tedious when we want to store each and every real world objects in the database as we will have to define another column(meta data- Horizontally increment in the database). To overcome this NO SQL is a very good solution, where we store the data in document form say real world object form, this way we will increase the database only in one direction. Let’s take a scenario where an end use is accessing multiple web application. Here we want to store each and every action performed by user so that we can track his interest and next time we can display few suggestion as advertisement to the user.

Note that, MongoDB isn't created and shouldn't be used the same as a SQL database. SQL (and other relational databased) store relational data, that is that data in table A can be set up to have direct relations to information in table B. MongoDB doesn't have this ability, and can therefore drops a lot of overhead. Hence MongoDB is usually used to store lists, not relations.
Drawback with mongodb, Add in the fact that it isn't not quite ACID compliant yet (though it has taken large strides since it was first introduced) and that's the bulk of the speed differences.
In practice, the non-transactional model of MongoDB has the following implications:

No rollbacks. Your code must function without rollbacks. Check all programmatic conditions before performing the first database write operation. Order your write operations such that the most important operation occurs last.
Explicit locking. Your code may explicitly lock objects when performing operations. Thus, the application programmer has the capability to ensure "serializability" when required. Locking functionality will be available in late alpha / early beta release of MongoDB.
Database check on startup. Should the database abnormal terminate (rare), a database check procedure will automatically run on startup (similar to fschk).



Prerequisite:
1. Java driver for mongodb. Download from here.
2.  Basic knowledge of MongoDb.

Assumption:
All the required parameters are passed for reading the collection from mongoDB.

Here is a quick list of required params. passed to the service method.

serverNameUrl - This is the path of server where mongodb is running, for e.g. "localhost"

dbName - Name of the Database. say "University" database.

collectionName - Name of the collection.

fieldValuePair - Here we are recviing the Field Values in a String form with two seaprators(: ,). say we want 'Name','Empno','Dept' of all employee whose 'Dept=ABC'. then this value would be "Name,Empno,Dept:ABC".

fVSeaprator- this seaprator string used for field and value, here it is ":".

vFSeaprator- this seaprator string used in between fields here it is ",".

sortField- Sortfield. Say empno

sortDirection- Sortdirection Say "-1" DESC(default is DESC).

code starts from here!


package com.service.mongo;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.MongoClient;
import com.mongodb.util.JSON;
import com.xp.util.Utils;

public class TestGenericService {

public static void main(String[] args) {
    //Start. This return a JSON string.
    String result =readQueryOfMongo("localhost","test","employeeCollection","Name,Empno,Dept:ABC",":",",","Empno","");
    System.out.println(result);
}


public static String readQueryOfMongo(  

        String serverNameUrl ,
        String dbName ,
        String collectionName,
        String fieldValuePair,
        String fVSeaprator,
        String vFSeaprator,
        String sortField,
        String sortDirection
)
{
    DB db;
    DBCollection table = null;
    DBCursor cursor = null;
    String result=null;
    BasicDBObject sortPredicate = new BasicDBObject();
    try
    {

        Map<String, String> fieldValuePairMap = new HashMap<String, String>();

        System.out.println("ServerName:"+serverNameUrl+"\nDatabase Name:"+dbName+"\nCollection Name:"+collectionName);

        //Configure the server, db and collection.
        MongoClient mongoClient = new MongoClient( serverNameUrl );

        db = mongoClient.getDB( dbName );

        System.out.println(db.getLastError());

        if (db.collectionExists(collectionName))
        {
            table = db.getCollection(collectionName);

        }
        else
        {
            throw new Exception("Collection doesn't exist");
        }

        //Define SortPredicate.
        if(sortField!= null)
        {
            if(sortDirection==null ||sortDirection.trim().length()==0)
                sortDirection="-1";//Default sort-order should be DESC.

            sortPredicate.put(sortField, Integer.parseInt(sortDirection));
        }

        if (null != fieldValuePair && fieldValuePair.trim().length() > 0)

        {
            BasicDBObject searchQuery = new BasicDBObject();

            fieldValuePairMap = parseStringToMap(fieldValuePair, fVSeaprator, vFSeaprator);

            System.out.println(fieldValuePairMap.size());

            BasicDBObject fields1 = new BasicDBObject("_id",false);


            if(fieldValuePairMap.size()>0)
            {
                Set keySet  = fieldValuePairMap.keySet();
                Iterator keyIter = keySet.iterator();
                String tempKey;
                while (keyIter.hasNext()) 
                {
                    tempKey = keyIter.next().toString();
                    fields1.append(tempKey, true);
                    if(fieldValuePairMap.get(tempKey)!=null)
                        searchQuery.put(tempKey, fieldValuePairMap.get(tempKey));
                }

                cursor = table.find(searchQuery,fields1).sort(sortPredicate);
            }

        }
        else
        {
            cursor = table.find().sort(sortPredicate);
        }
        result = parseStubJson(cursor, collectionName);

    }catch (Exception e) {
        e.printStackTrace();

    }
    return result;
}

// The below method is used for parsing  the  mongdb result to JSON string.

public static String parseStubJson(DBCursor dBCursor, String stubName)
{
    System.out.println("Creating a JSON stub of:"+stubName);

    String response="{"+"\""+stubName+"\":[";
    int i=0;
    int j= dBCursor.count();
    while (dBCursor.hasNext()) 
    {
        i++;
        response += JSON.parse(dBCursor.next().toString());
        if(j>i)
            response +=",";
    }

    response += "]}";
    return response;
}

//This method parse string(fields-values) to  a map. with  the help of separators.

public static Map<String, String>  parseStringToMap(String kerValuePair,String seprator1,String seprator2)
{
    Map<String, String> myMap = new HashMap<String, String>();

    String[] pairs = kerValuePair.split(seprator2);
    for (int i=0;i<pairs.length;i++) {
        String pair = pairs[i];
        String[] keyValue = pair.split(seprator1);
        if(keyValue.length > 1)
            myMap.put(keyValue[0], keyValue[1]);
        else
            myMap.put(pairs[i], null);
    }

    Iterator itr = myMap.entrySet().iterator();
    while (itr.hasNext()) {
        Object object = (Object) itr.next();
        System.out.println(object.toString());
    }
    return myMap;
}
}

Note: This above code returns result in JSON string form, You can use any parser at client end and convert the result in required list or stub. Yes, you may feel that the above example is written with SQL mindset, and this is not the best use of NOSQL (mongodb), but to understand basic read operation in mongodb this is very much useful.

** Facing any prob with mongodb and java, do write to me. Thanks!