'Java Spring Reactive, returning one Mono<..> from many multiple requests
[Java, Spring Reactive, MongoDB] I'm currently trying to learn Reactive programming by doing and I found a challenge.
I have db object CategoryDB which looks like this:
@NoArgsConstructor
@Getter
@Setter
@Document(collection = DBConstraints.CATEGORY_COLLECTION_NAME)
class CategoryDB {
@Id
private String id;
private String name;
private String details = "";
@Version
private Long version;
private String parentCategoryId;
private Set<String> childCategoriesIds = new HashSet<>();
}
In a service layer I want to use model object Category.
@Getter
@Builder
public class Category {
private String id;
private String name;
private String details;
private Long version;
private Category parentCategory;
@Builder.Default
private Set<Category> childCategories = new HashSet<>();
}
I want to create Service with method Mono<Category getById(String id). In this case I want to fetch just one level of childCategories and direct parent Category. By default repository deliver Mono findById(..) and Flux findAllById(..) which I could use, but I'm not sure what would be the best way to receive expected result. I would be grateful for either working example or directions where can I find solution for this problem.
Solution 1:[1]
I've spent some time to figure out solution for this problem, but as I'm learning I don't know if it's good way of solving problems.
Added some methods to Category:
@Getter
@Builder
public class Category {
private String id;
private String name;
private String details;
private Long version;
private Category parentCategory;
@Builder.Default
private Set<Category> childCategories = new HashSet<>();
public void addChildCategory(Category childCategory) {
childCategory.updateParentCategory(this);
this.childCategories.add(childCategory);
}
public void updateParentCategory(Category parentCategory) {
this.parentCategory = parentCategory;
}
}
Function inside service would look like this:
@Override
public Mono<Category> findById(String id) {
return categoryRepository.findById(id).flatMap(
categoryDB -> {
Category category = CategoryDBMapper.INSTANCE.toDomain(categoryDB);
Mono<CategoryDB> parentCategoryMono;
if(!categoryDB.getParentCategoryId().isBlank()){
parentCategoryMono = categoryRepository.findById(categoryDB.getParentCategoryId());
}
else {
parentCategoryMono = Mono.empty();
}
Mono<List<CategoryDB>> childCategoriesMono = categoryRepository.findAllById(categoryDB.getChildCategoriesIds()).collectList();
return Mono.zip(parentCategoryMono, childCategoriesMono, (parentCategoryDB, childCategoriesDB) -> {
Category parentCategory = CategoryDBMapper.INSTANCE.toDomain(parentCategoryDB);
category.updateParentCategory(parentCategory);
childCategoriesDB.forEach(childCategoryDB -> {
Category childCategory = CategoryDBMapper.INSTANCE.toDomain(childCategoryDB);
category.addChildCategory(childCategory);
});
return category;
});
}
);
}
Where mapper is used for just basic properties: @Mapper interface CategoryDBMapper {
CategoryDBMapper INSTANCE = Mappers.getMapper(CategoryDBMapper.class);
@Mappings({
@Mapping(target = "parentCategoryId", source = "parentCategory.id"),
@Mapping(target = "childCategoriesIds", ignore = true)
})
CategoryDB toDb(Category category);
@Mappings({
@Mapping(target = "parentCategory", ignore = true),
@Mapping(target = "childCategories", ignore = true)
})
Category toDomain(CategoryDB categoryDB);
}
As I said I don't know if it's correct way of solving the problem, but it seem to work. I would be grateful for review and directions.
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 | Robert Radzik |
