Search code examples
javareactive-programmingspring-webflux

Spring webflux convert flux to DTO after grouping certain fields into a child DTO object


My rest api is using Spring Webflux. While fetching an Entity from Postgres which is denormalized table, I am getting multiple rows for the same object. While converting to DTO, I need to iterate through multiple User objects for the same user and make a list of all departments he/she is part of and then add the list to the DTO. This way, I can send back a single row per User. How can I achieve this without blocking.

@Entity
public Class User {

    private int id;
    private String name;
    private String department;
    private String departmentArea;

}

public Class UserDTO {
    
    private int id;
    private String name;
    private List<DepartmentDTO> departmentDTO;
    
}

How to I convert the User objects into a UserDTO with a list of DepartmentDTO

Current implementation in service

userRepo.findAllUsersByIds().map(mapper::mapUserDTO));

Solution

  • You can use groupBy operator to group by id and then map every group into a UserDTO

    Flux<UserDTO> res = userRepo.findAllUsersByIds()
            .groupBy(user -> user.getId())
            .flatMap(group ->
                    group.collectList()
                            .map(users -> {
                                var userDto = new UserDTO();
                                userDto.setId(group.key());
                                userDto.setName(users.get(0).getName());
                                userDto.setDepartmentDTO(
                                        users.stream()
                                                .map(user -> {
                                                    var deptDto = new DepartmentDTO();
                                                    deptDto.setName(user.getDepartment());
                                                    deptDto.setArea(user.getDepartmentArea());
                                                    return deptDto;
                                                })
                                                .toList()
                                );
                                return userDto;
                            })
            );