Review List Service

In this lesson, we'll implement the functionality to list restaurant reviews with sorting and pagination capabilities.

Service Implementation

Let's declare the listReviews method in our ReviewService interface:

public interface ReviewService { // ... Page<Review> listReviews(String restaurantId, Pageable pageable); }

The method accepts three parameters:

  • restaurantId - identifies the restaurant whose reviews we want to retrieve
  • pageable - contains pagination information like page size, number and sorting preferences

The implementation in ReviewServiceImpl handles sorting and pagination manually because reviews are stored as nested objects within the restaurant document:

@Override public Page<Review> getRestaurantReviews(String restaurantId, Pageable pageable) { // Get the restaurant or throw an exception if not found Restaurant restaurant = getRestaurantOrThrow(restaurantId); // Create a list of reviews List<Review> reviews = new ArrayList<>(restaurant.getReviews()); // Apply sorting based on the Pageable's Sort Sort sort = pageable.getSort(); if (sort.isSorted()) { Sort.Order order = sort.iterator().next(); String property = order.getProperty(); boolean isAscending = order.getDirection().isAscending(); Comparator<Review> comparator = switch (property) { case "datePosted" -> Comparator.comparing(Review::getDatePosted); case "rating" -> Comparator.comparing(Review::getRating); default -> Comparator.comparing(Review::getDatePosted); }; reviews.sort(isAscending ? comparator : comparator.reversed()); } else { // Default sort by date descending reviews.sort(Comparator.comparing(Review::getDatePosted).reversed()); } // Calculate pagination boundaries int start = (int) pageable.getOffset(); // Handle empty pages if (start >= reviews.size()) { return new PageImpl<>(Collections.emptyList(), pageable, reviews.size()); } int end = Math.min((start + pageable.getPageSize()), reviews.size()); // Create the page of reviews return new PageImpl<>(reviews.subList(start, end), pageable, reviews.size()); }

Manual Pagination Considerations

We implement manual pagination because reviews are stored as nested objects within the restaurant document.

Using a separate index for reviews would eliminate the need for manual pagination, but would require:

  • Additional data synchronization logic
  • More complex data consistency checks
  • Increased storage requirements

For our use case, the benefits of keeping reviews nested within restaurants outweigh the cost of manual pagination implementation.

Summary

  • Implemented listReviews method in ReviewService
  • Added sorting options for reviews by date and rating
  • Implemented manual pagination for nested review objects
  • Reviews are retrieved from the restaurant document
© 2026 Devtiro Ltd. All rights reserved