Search code examples
mongodbmongodb-queryspring-data-mongodbmongorepository

Use limit and skip in MongoRepository<Customer,String>


We are working on a project to get data from mongoDB. We have created repository class as below

@Repository
public interface CustomerRepository extends MongoRepository<Customer,String>{
     List<Customer> customers = findByCustomerId(final String customerId);
}

We are looking to add skip/offset and limit parameters to be used as part of findByCustomerId method. where limit is used to define number of records returned and skip/offset defines the number of records after which we need to get the records.

Please help how we can get this implemented in best way using MongoRepository.


Solution

  • There are two ways to do this.

    1. Use of @Aggregation annotation as mentioned in this answer. https://stackoverflow.com/a/71292598/8470055

    For example:

    @Repository
    public interface CustomerRepository extends MongoRepository<Customer,String>{
    
      @Aggregation(pipeline = {
        "{ '$match': { 'customerId' : ?0 } }", 
        "{ '$sort' : { 'customerId' : 1 } }", 
        "{ '$skip' : ?1 }", 
        "{ '$limit' : ?2 }"
      })
      List<Customer> findByCustomerId(final String customerId, int skip, int limit);
    
      @Aggregation(pipeline = {
        "{ '$match': { 'customerId' : ?0 } }", 
        "{ '$sort' : { 'customerId' : 1 } }", 
        "{ '$skip' : ?1 }"
      })
      Page<Customer> findCustomers(final String customerId, int skip, Pageable pageable);
    
    }
    

    The $match operator's query might need to be modified so that it better reflects the condition that needs to be satisfied by the matching documents.

    1. Use Pageable argument in the query method and supply the PageRequest from the layer that calls the Repository method as shown in this answer. https://stackoverflow.com/a/10077534/8470055

    For the code snippet in the question this then becomes.

    @Repository
    public interface CustomerRepository extends MongoRepository<Customer,String> {
    
      Page<Customer> findByCustomerId(final String customerId, Pageable pageable);
    
    }
    
    // -------------------------------------------------------
    // Call the repository method from a service
    @Service
    public class CustomerService {
    
      private final CustomerRepository customerRepository;
    
      public CustomerService(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
      }
    
      public List<Customer> getCustomers(String customerId, int skip, int limit) {
        // application-specific handling of skip and limit arguments
        int page = 1; // calculated based on skip and limit values
        int size = 5; // calculated based on skip and limit values
        Page<Customer> page = customerRepository.findByCustomerId(customerId, 
                     PageRequest.of(page, size, Sort.Direction.ASC, "customerId"));
        List<Customer> customers = page.getContent();
    
        /*
        Here, the query method will retrieve 5 documents from the second 
        page.
        It skips the first 5 documents in the first page with page index 0. 
        This approach requires calculating the page to retrieve based on 
        the application's definition of limit/skip.
        */
        return Collections.unmodifiableList(customers);
      }
    }
    

    The aggregation approach is more useful. If the result is limited to a few documents then the query method can return List<Customer>. If there a lot of documents then the query method can be modified to use Pageable argument that returns Page<Customer> to page over the documents.

    Refer to both Spring Data and MongoDB documentation.

    https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#mongo.repositories

    https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#mongodb.repositories.queries.aggregation

    https://docs.spring.io/spring-data/mongodb/docs/3.2.10/api/org/springframework/data/mongodb/repository/Aggregation.html

    https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Pageable.html

    https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/PageRequest.html

    MongoDB Aggregation - https://www.mongodb.com/docs/manual/meta/aggregation-quick-reference/

    Dynamic Queries

    Custom Spring Data repository implementation along with use of MongoTemplate should help in implementing dynamic queries.

    Custom Repositories - https://docs.spring.io/spring-data/mongodb/docs/3.2.10/reference/html/#repositories.custom-implementations

    MongoTemplate - https://docs.spring.io/spring-data/mongodb/docs/3.2.10/api/org/springframework/data/mongodb/core/MongoTemplate.html