Use Sub document API LookupIN to map multile fields to pojo using reflection

Hi Team,

I have a pojo Employee with four fields (String name, int age, String email ,int phone)
The Actual document in couchbase contains around 20 fields. But I need to select only the above four fields mentioned in pojo.

Approach 1:

I cannot use a kv api like get , because it will return the entire object.
Approach 2

I could have written the below query to apply projection.
select name,age,email,phone from emp_bucket use keys “sample”
But it involves the query service and data service, since I know the document key , I am planning to use sub document API which will involve only the data service.

Approach 3
Use subdocument API lookupIn to get the fields and build the pojo using reflection.
code
public static void main(String args) {
Cluster cluster = Cluster.connect(host, userName, password);
Bucket bucket = cluster.bucket(bucketName);
Collection empCollection = bucket.defaultCollection();
String documentId = “sample123”;

code:

public static void main(String[] args) {
	Cluster cluster = Cluster.connect(host, userName, password);
	Bucket bucket = cluster.bucket(bucketName);
	Collection empCollection = bucket.defaultCollection();
	String documentId = "sample123";

	Employee employee = new Employee();
	Class<?> clazz = employee.getClass();
	Field[] fields = clazz.getDeclaredFields();

	List<LookupInSpec> specs = new ArrayList<>();
	for (Field field : fields) {
		specs.add(LookupInSpec.get(field.getName()));
	}

	LookupInResult lookupResult = empCollection.lookupIn(documentId, specs);
	int index = 0;
	JsonNode value = null;
	for (Field field : fields) {
		field.setAccessible(true);
		Class<?> fieldType = field.getType();
		try {
			value = lookupResult.contentAs(index, JsonNode.class);
			if (fieldType.equals(String.class)) {
				field.set(employee, value.toString());
			} else if (fieldType.equals(Long.class) || fieldType.equals(long.class)) {
				field.set(employee, Long.valueOf(value.toString()));
			} else if (fieldType.equals(Integer.class) || fieldType.equals(int.class)) {
				field.set(employee, Integer.valueOf(value.toString()));
			}
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (Exception e3) {
			System.out.println("Exception : " + e3);
		}
		index++;
	}

	System.out.println("Employee : " + employee);
}

The only thing I am worried is at line lookupResult.contentAs(index, JsonNode.class);
will this be returning the data always in same order ? so that value of one fields does not get mapped to another field?
Can some one tell me if there is a better approach to this problem?

1 Like

Hi @Manzoor128
The lookupResult will contain the same fields in the same order as how you request them in the lookupIn.
You can also use the get-with-projection feature added in SDK3:

GetResult gr = collection.get("id", GetOptions.getOptions().project("path1", "path2"));
YourPojo pojo = gr.contentAs(YourPojo.class);
1 Like

Thank You Graham.

I will check the Get Approach with projection

2 Likes