There are two ways to do this.
- 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.
- 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