'Spring Data Mongodb Aggregation - Group by nested objects and build DTO

I have the following Employee data in MongoDB

{
  "_id": {
    "$oid": "625f09bb1a96bf42ff4c4006"
  },
  "employeeId": 1234,
  "email": "[email protected]",
  "firstName": "Jason",
  "lastName": "Stuart",
  "currentCTC": 1201117.61,
  "department": {
    "$ref": "department",
    "$id": {
      "$oid": "625f09bb1a96bf42ff4c4005"
    }
  }
}
{
  "_id": {
    "$oid": "625f09bb1a96bf42ff4c4006"
  },
  "employeeId": 1235,
  "email": "[email protected]",
  "firstName": "Jasons",
  "lastName": "Stuarts",
  "currentCTC": 1201117.61,
  "department": {
    "$ref": "department",
    "$id": {
      "$oid": "625f09bb1a96bf42ff4c4005"
    }
  }
}

My Spring @Document looks like this:

// Employee.java
@Data
@Document
public class Employee {
    @Id
    private String id;
    private Long employeeId;
    private String email;
    private String firstName;
    private String middleName;
    private String lastName;
    private Gender gender;
    private double currentCTC;

    @DBRef
    private Department department;
}

// Department.java
@Document
@Data
public class Department {
    @Id
    private String id;
    private String name;
}

Now, my requirement is to find the sum of salaries Department-wise.. I need the data to be in the following way:

[
  {
    "department": {
      "id": "625f09bb1a96bf42ff4c4006",
      "name": "Engineering"
    },
    "cost": 31894773.01
  },
  {
    "department": {
      "id": "625f09bb1a96bf42ff4c4006",
      "name": "Marketing"
    },
    "cost": 4552325.25
  }
]

I created an aggregate function like this in Spring Data:

public List<DepartmentCost> getDepartmentCosting() {
        GroupOperation groupByDepartment = group("department").sum("currentCTC").as("cost").first("$$ROOT").as("department");
        Aggregation aggregation = Aggregation.newAggregation(groupByDepartment);
        
        AggregationResults<DepartmentCost> results = mongoTemplate.aggregate(aggregation, "employee", DepartmentCost.class);
        return results.getMappedResults();
    }

And my expected DepartmentCost.java

@Data
@Document
public class DepartmentCost {
    @DBRef
    private Department department;
    private double cost;
}

Now when I try this API out, I get the data correctly, but I do not get department name. It comes as null. I get a response like

[
  {
    "department": {
      "id": "625f09bb1a96bf42ff4c4006",
      "name": null,
    },
    "cost": 2241117.6100000003
  },
  {
    "department": {
      "id": "625f09bb1a96bf42ff4c400a",
      "name": null,
    },
    "cost": 14774021.43
  },
  {
    "department": {
      "id": "625f09bc1a96bf42ff4c4013",
      "name": null,
    },
    "cost": 14879633.97
  }
]

How can I get the department details expanded in my model? Please help..



Solution 1:[1]

After a couple of attempts, I figured it out. All I had to do was this:

GroupOperation groupByDepartment = group("department").sum("currentCTC").as("cost").first("$department").as("department");

as opposed to:

GroupOperation groupByDepartment = group("department").sum("currentCTC").as("cost").first("$$ROOT").as("department");

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sriram Sridharan