diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java index 824bd8e60..5f104634d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java @@ -15,6 +15,7 @@ */ package org.springframework.data.mongodb.repository.query; +import java.util.Collections; import java.util.List; import org.springframework.core.convert.ConversionService; @@ -254,10 +255,26 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { Object execute(Query query) { MongoEntityMetadata metadata = method.getEntityInformation(); + + int overallLimit = query.getLimit(); long count = operations.count(query, metadata.getCollectionName()); + count = overallLimit != 0 ? Math.min(count, query.getLimit()) : count; - List result = operations.find(query.with(pageable), metadata.getJavaType(), metadata.getCollectionName()); + boolean pageableOutOfScope = pageable.getOffset() > query.getLimit(); + if (pageableOutOfScope) { + return new PageImpl(Collections.emptyList(), pageable, count); + } + + // Apply raw pagination + query = query.with(pageable); + + // Adjust limit if page would exceed the overall limit + if (overallLimit != 0 && pageable.getOffset() + pageable.getPageSize() > overallLimit) { + query.limit(overallLimit - pageable.getOffset()); + } + + List result = operations.find(query, metadata.getJavaType(), metadata.getCollectionName()); return new PageImpl(result, pageable, count); } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/PartTreeMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/PartTreeMongoQuery.java index b8a34f118..29eeb2418 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/PartTreeMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/PartTreeMongoQuery.java @@ -73,6 +73,10 @@ public class PartTreeMongoQuery extends AbstractMongoQuery { MongoQueryCreator creator = new MongoQueryCreator(tree, accessor, context, isGeoNearQuery); Query query = creator.createQuery(); + if (tree.isLimiting()) { + query.limit(tree.getMaxResults()); + } + String fieldSpec = this.getQueryMethod().getFieldSpecification(); if (!StringUtils.hasText(fieldSpec)) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java index 757822de8..28c6aa7c9 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java @@ -917,5 +917,54 @@ public abstract class AbstractPersonRepositoryIntegrationTests { assertThat(result.getContent(), hasSize(2)); assertThat(result.getTotalPages(), is(2)); assertThat(result.getTotalElements(), is(3L)); + + } + + /** + * @see DATAMONGO-950 + */ + @Test + public void shouldLimitCollectionQueryToMaxResultsWhenPresent() { + + repository.save(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), new Person("Bob-3", + "Dylan"), new Person("Bob-4", "Dylan"), new Person("Bob-5", "Dylan"))); + List result = repository.findTop3ByLastnameStartingWith("Dylan"); + assertThat(result.size(), is(3)); + } + + /** + * @see DATAMONGO-950 + */ + @Test + public void shouldNotLimitPagedQueryWhenPageRequestWithinBounds() { + + repository.save(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), new Person("Bob-3", + "Dylan"), new Person("Bob-4", "Dylan"), new Person("Bob-5", "Dylan"))); + Page result = repository.findTop3ByLastnameStartingWith("Dylan", new PageRequest(0, 2)); + assertThat(result.getContent().size(), is(2)); + } + + /** + * @see DATAMONGO-950 + */ + @Test + public void shouldLimitPagedQueryWhenPageRequestExceedsUpperBoundary() { + + repository.save(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), new Person("Bob-3", + "Dylan"), new Person("Bob-4", "Dylan"), new Person("Bob-5", "Dylan"))); + Page result = repository.findTop3ByLastnameStartingWith("Dylan", new PageRequest(1, 2)); + assertThat(result.getContent().size(), is(1)); + } + + /** + * @see DATAMONGO-950 + */ + @Test + public void shouldReturnEmptyWhenPageRequestedPageIsTotallyOutOfScopeForLimit() { + + repository.save(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), new Person("Bob-3", + "Dylan"), new Person("Bob-4", "Dylan"), new Person("Bob-5", "Dylan"))); + Page result = repository.findTop3ByLastnameStartingWith("Dylan", new PageRequest(2, 2)); + assertThat(result.getContent().size(), is(0)); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java index 3cde5acf8..d8ef7643f 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java @@ -302,4 +302,15 @@ public interface PersonRepository extends MongoRepository, Query */ @Query("{lastname:?0, address.street:{$in:?1}}") Page findByCustomQueryLastnameAndAddressStreetInList(String lastname, List streetNames, Pageable page); + + /** + * @see DATAMONGO-950 + */ + List findTop3ByLastnameStartingWith(String lastname); + + /** + * @see DATAMONGO-950 + */ + Page findTop3ByLastnameStartingWith(String lastname, Pageable pageRequest); + }