CouchDB is one of NoSQL database, uses JSON to store data, Javascript as its query language using MapReduce, and Http for an API.

Each document in db has a unique identifier (_id) and a revision(_rev) number.

CouchDB has a lots of benefits, I won’t list here :)

Import Couch in Project

We also import GOOGLE GSON package because we use it to transfer an object to json

dependencies {
  compile("org.lightcouch:lightcouch:0.1.8")
  runtime("org.lightcouch:lightcouch:0.1.8")
  compile("com.google.code.gson:gson:2.2.4")
  runtime("com.google.code.gson:gson:2.2.4")
}

Create a Factory Method of DbClient

import org.lightcouch.CouchDbClient;
import org.lightcouch.CouchDbProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class CouchDbClientFactory {
    @Autowired
    private ApplicationContext applicationContext;

    //@Value("${couchdb.createdb.if-not-exist}")
    protected boolean ifNotExist = true;
    @Value("${couchdb.username}")
    protected String username;
    @Value("${couchdb.password}")
    protected String password;
    @Value("${couchdb.host}")
    protected String host;
    @Value("${couchdb.protocol}")
    protected String protocol;
    @Value("${couchdb.port}")
    protected int port;

    public CouchDbClient getNewClientConnection(String dbName) {
        //super("application.properties");
        CouchDbProperties properties = new CouchDbProperties()
                .setDbName(dbName)
                .setCreateDbIfNotExist(ifNotExist)
                .setProtocol(protocol)
                .setHost(host)
                .setPort(port)
                .setUsername(username)
                .setPassword(password);
        CouchDbClient c = (CouchDbClient) applicationContext.getBean("couchDbClientConnection", properties);

        try {
            c.syncDesignDocsWithDb();
        } catch (NullPointerException n) {
            //I think this happends because there are no design documents specified.
        }
        return c;
    }
}

Use in Repository

@Repository
public class DemoRepository{

	@Autowired
	private CouchDbClientFactory dbClientFactory;

	public CouchDbClient dbClient;
	
	@PostConstruct
	private void setupViews() {
		init(); // Set up views here
	}
}

Couch view method

import java.util.HashMap;

import org.lightcouch.Document;

public class CouchView extends Document {
	private String language; 
	private HashMap<String,Object> views;
	
	public CouchView(String name) {
		this.setLanguage("javascript");
		this.setViews(null);
		String id = "_design/" + name; 
		this.setId(id); 
	}

	public String getLanguage() {
		return language;
	}

	public void setLanguage(String language) {
		this.language = language;
	}

	public HashMap<String,Object> getViews() {
		return views;
	}

	public void setViews(HashMap<String,Object> views) {
		this.views = views;
	}
}

Create Document Model

Model object can be stored in Couch

public class Job {

  private Long createdDate;
  private String parameterId; //your id
  private String username;
  
  //GETTERS and SETTERS here
}

Create views

  1. Connect to database
  2. Delete the view if it exists on startup
      try { 
     DesignDocument designDoc1 = dbClient.design().getFromDb("_design/jobs");
     dbClient.remove(designDoc1);
      } catch (NoDocumentException e) {/* that's ok, just continue */ }
    
  3. Create views and save it to db
protected void init() {
    try {
        this.dbClient = dbClientFactory.getNewClientConnection("databaseName"));

        try {
            DesignDocument designDoc1 = dbClient.design().getFromDb("_design/jobs");
            dbClient.remove(designDoc1);
        } catch (NoDocumentException e) {/* that's ok, just continue */ }

        // recreate the view
        CouchView jobsView = new CouchView("jobs");
        HashMap<String, Object> views = new HashMap<String, Object>();
        HashMap<String, Object> processableJobsView = new HashMap<String, Object>();

        //byusername
        HashMap<String, Object> byUsername = new HashMap<String, Object>();
        byUsername.put("map", "function(job) { emit(job.username, job); }");
        views.put("byusername", byUsername);

        //bydate
        HashMap<String, Object> byCreatedDate = new HashMap<String, Object>();
        byCreatedDate.put("map",
                "function(job) { var currentTime=(new Date()).getTime(); "
                        + " var numberOfDays= Math.round ((currentTime-job.createdDate)/(1000*3600*24)); "
                        + " if(job.status != undefined && job.reportPath != undefined) { "
                        + "    emit( numberOfDays,job);"
                        + " } } "
        );
        views.put("bydate", byCreatedDate);

        HashMap<String, Object> allJobs = new HashMap<String, Object>();
        allJobs.put("map", "function(job) {  " +
                "if(job.status != undefined && job.reportPath != undefined){"
                + "emit( job.id,job);}} ");
        views.put("alljobs", allJobs);
        jobsView.setViews(views);
        this.dbClient.post(jobsView);
    } catch (DocumentConflictException ex) {
        // if this happens it means that the document was already created
    }
}

Use couch views

Couch privides metho to manipulate documents in it

public Job getJobById(String id) {

  Job j = this.dbClient.find(Job.class,id);
  return j;
}

public void deleteJobById(String id) {

  Job job = this.getJobById(id);
  try { deleteJobZipAttachement(job); } catch(Exception e) {} //if not found no problem

  JsonObject json = this.dbClient.find(JsonObject.class, id);
  this.dbClient.remove(json.get("_id").getAsString(), json.get("_rev").getAsString());
}

public Job getJobByGeneratedid(String id) {
  
  List<JsonObject> jsons = this.dbClient.view("jobs/bygeneratedid")
      .includeDocs(true)
      .key(id)
      .query(JsonObject.class);
  
  if(jsons == null || jsons.size()!=1) {
    throw new NoDocumentException("Failed to get exactly one document back by generated id");
  }
  
  return this.getJobById(jsons.get(0).get("_id").getAsString());
}