Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Generic Search in MongoDB With Java

DZone 's Guide to

Generic Search in MongoDB With Java

There is no need to put a Service Class for every collection — one method could do that!

· Java Zone ·
Free Resource

In this post, we will create a generic method to search data in MongoDB database via MongoDB driver API. There is no need to put specific Service Class for every collection; one method could do that

  •  QueryParam: Class to specify field name, value, and operator (equal, greather than, etc.)
package com.ahajri.mongo.queries;

public class QueryParam{

  //collection field name
private String fieldName;
//Operator name 
private String operator;
//value 
private Object value;


public QueryParam(String fieldName, String operator, Object value) {
super();
this.fieldName = fieldName;
this.operator = operator;
this.value = value;
}

public String getFieldName() {
return fieldName;
}

public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}

public String getOperator() {
return operator;
}

public void setOperator(String operator) {
this.operator = operator;
}

public Object getValue() {
return value;
}

public void setValue(Object value) {
this.value = value;
}



}


Operators are grouped in a Java enum, as shown below:

package com.ahajri.mongo.enums;

/**
 * 
 * @author ahajri
 * 
 * 
 *         <p>
 *         $eq Matches values that are equal to a specified value.
 *         </p>
 *         <p>
 *         $gt Matches values that are greater than a specified value.
 *         </p>
 *         <p>
 *         $gte Matches values that are greater than or equal to a specified
 *         value.
 *         </p>
 *         <p>
 *         $in Matches any of the values specified in an array.
 *         </p>
 *         <p>
 *         $lt Matches values that are less than a specified value.
 *         </p>
 *         <p>
 *         $lte Matches values that are less than or equal to a specified value.
 *         </p>
 *         <p>
 *         $ne Matches all values that are not equal to a specified value.
 *         </p>
 *         <p>
 *         $nin Matches none of the values specified in an array.
 *         </p>
 *
 */
public enum OperatorEnum {
EQ, GT, GTE, IN, LT, LTE, NE, NIN;
}


Now, let's explore our Mongo service accessor class; our database is supposed to be hosted on MLab, and application.yml contains the required information, as shown below:

mlab:
  db.host: ${MLAB_DB_HOST}
  db.name: ${MLAB_DB_NAME}
  db.user: ${MLAB_DB_USER}
  db.port: ${MLAB_DB_PORT}
  db.password: ${MLAB_DB_PASSWORD}
  api.key: ${MLAB_API_KEY}

spring:
  data.mongodb.uri: mongodb://${MLAB_DB_USER}:${MLAB_DB_PASSWORD}@${MLAB_DB_HOST}:${MLAB_DB_PORT}/${MLAB_DB_NAME}
  servlet.multipart.enabled: true
  servlet.multipart.file-size-threshold: 2KB
  servlet.multipart.max-file-size: 200MB
  servlet.multipart.max-request-size: 215MB


Our search method open and close the connection in an atomic way where we only give the collection name and array of the QueryParam class. It looks like this:

package com.ahajri.hc.mongo.cloud;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.annotation.PostConstruct;

import org.bson.Document;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.ahajri.mongo.enums.ErrorMessageEnum;
import com.ahajri.mongo.exception.MyException;
import com.ahajri.mongo.enums.QueryParam;
import com.ahajri.mongo.utils.JsonUtils;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.FindOneAndReplaceOptions;

/**
 * @author ahajri
 */
@Service
public class MLabMongoService {

private String cloudMongUrl;

private MongoDatabase db;

private MongoClient client;

@Value("${mlab.api.key}")
protected String apiKey;

@Value("${mlab.db.user}")
protected String dbUser;

@Value("${mlab.db.password}")
protected String dbPwd;

@Value("${mlab.db.name}")
protected String dbName;

@Value("${mlab.db.port}")
protected String dbPort;

@Value("${mlab.db.host}")
protected String dbHost;

public MLabMongoService() {
}

@PostConstruct
public void init() {
      //create MLab url connection 
  cloudMongUrl = "mongodb://" + dbUser + ":" + dbPwd + "@" + dbHost + ":" + dbPort + "/" + dbName;
}

/**
 * Open Mongo Connection
 */
private void begin() {
MongoClientURI uri = new MongoClientURI(cloudMongUrl);
client = new MongoClient(uri);
db = client.getDatabase(uri.getDatabase());
}



/**
 * 
 * Search document
 * 
 * @param collectionName:
 *            Collection name
 * @param qp
 *            : Query Parameters
 * @return list of found documents
 * @throws BusinessException
 */
public List<Document> search(String collectionName, QueryParam... qp) throws BusinessException {
try {
      begin();
      MongoCollection<Document> collection = db.getCollection(collectionName);
      List<Document> result = new ArrayList<>();
      Document query = new Document();
      Arrays.asList(qp).stream().forEach(p -> {
          String operator = p.getOperator();
          String fieldName = p.getFieldName();
          Object value = p.getValue();
          switch (operator) {
          case "EQ":
          query.append(fieldName, new Document().append("$eq", value));
          break;
          case "NE":
          query.append(fieldName, new Document().append("$ne", value));
          break;
          case "GT":
          query.append(fieldName, new Document().append("$gt", value));
          break;
          case "GTE":
          query.append(fieldName, new Document().append("$gte", value));
          break;
          case "LT":
          query.append(fieldName, new Document().append("$lt", value));
          break;
          case "LTE":
          query.append(fieldName, new Document().append("$lte", value));
          break;
          case "IN":
          query.append(fieldName, new Document().append("$in", value));
          break;
          case "NIN":
          query.append(fieldName, new Document().append("$nin", value));
          break;
          default:
          break;
          }

});

  FindIterable<Document> iterable = collection.find(query);
    if (iterable.first() == null) {
    throw new Exception(ErrorMessageEnum.FIND_DOCUMENT_KO.getMessage());
    }
    for (Document document : iterable) {
    result.add(document);
    }

close();
return result;

  } catch (Exception e) {
          throw new MyException(e, ErrorMessageEnum.FIND_DOCUMENT_KO.getMessage());
  }
}


  private void close() {
      if (client != null) {
          client.close();
      }
  }

}


To test the method,QueryParams must be provided in a programmatically. For example:

QueryParam[] qps = new QueryParam[1];

qps[0] = new QueryParam("email", OperatorEnum.EQ.name(), "myemail@mail.com");


Hope this was helpful!

Topics:
java ,mongo db ,spring

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}