diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java index c7c94eed8..21cee1f39 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java @@ -115,6 +115,20 @@ public interface ExecutableFindOperation { * Never {@literal null}. */ CloseableIterator stream(); + + /** + * Get the number of matching elements. + * + * @return total number of matching elements. + */ + long count(); + + /** + * Check for the presence of matching elements. + * + * @return {@literal true} if at least one matching element exists. + */ + boolean exists(); } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java index 2c54a4b53..67f8ddf6b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java @@ -41,6 +41,8 @@ import com.mongodb.client.FindIterable; */ class ExecutableFindOperationSupport implements ExecutableFindOperation { + private static final Query ALL_QUERY = new BasicQuery(new Document()); + private final MongoTemplate template; /** @@ -61,7 +63,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation { Assert.notNull(domainType, "DomainType must not be null!"); - return new FindOperationSupport<>(template, domainType, domainType, null, null); + return new FindOperationSupport<>(template, domainType, domainType, null, ALL_QUERY); } /** @@ -142,10 +144,20 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation { return () -> template.geoNear(nearQuery, domainType, getCollectionName(), returnType); } + @Override + public long count() { + return template.count(query, domainType, getCollectionName()); + } + + @Override + public boolean exists() { + return template.exists(query, domainType, getCollectionName()); + } + private List doFind(CursorPreparer preparer) { - Document queryObject = query != null ? query.getQueryObject() : new Document(); - Document fieldsObject = query != null ? query.getFieldsObject() : new Document(); + Document queryObject = query.getQueryObject(); + Document fieldsObject = query.getFieldsObject(); return template.doFind(getCollectionName(), queryObject, fieldsObject, domainType, returnType, getCursorPreparer(query, preparer)); @@ -153,8 +165,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation { private CloseableIterator doStream() { - return template.doStream(query != null ? query : new BasicQuery(new Document()), domainType, getCollectionName(), - returnType); + return template.doStream(query, domainType, getCollectionName(), returnType); } private CursorPreparer getCursorPreparer(Query query, CursorPreparer preparer) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java index 44ed9d138..d6ee7afb7 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupportTests.java @@ -31,6 +31,7 @@ import org.springframework.data.geo.Point; import org.springframework.data.mongodb.core.index.GeoSpatialIndexType; import org.springframework.data.mongodb.core.index.GeospatialIndex; import org.springframework.data.mongodb.core.mapping.Field; +import org.springframework.data.mongodb.core.query.BasicQuery; import org.springframework.data.mongodb.core.query.NearQuery; import org.springframework.data.util.CloseableIterator; @@ -242,6 +243,43 @@ public class ExecutableFindOperationSupportTests { assertThat(template.query(Person.class).first()).isNotEmpty(); } + @Test // DATAMONGO-1734 + public void countShouldReturnNrOfElementsInCollectionWhenNoQueryPresent() { + assertThat(template.query(Person.class).count()).isEqualTo(2); + } + + @Test // DATAMONGO-1734 + public void countShouldReturnNrOfElementsMatchingQuery() { + + assertThat(template.query(Person.class).matching(query(where("firstname").is(luke.getFirstname()))).count()) + .isEqualTo(1); + } + + @Test // DATAMONGO-1734 + public void existsShouldReturnTrueIfAtLeastOneElementExistsInCollection() { + assertThat(template.query(Person.class).exists()).isTrue(); + } + + @Test // DATAMONGO-1734 + public void existsShouldReturnFalseIfNoElementExistsInCollection() { + + template.remove(new BasicQuery("{}"), STAR_WARS); + + assertThat(template.query(Person.class).exists()).isFalse(); + } + + @Test // DATAMONGO-1734 + public void existsShouldReturnTrueIfAtLeastOneElementMatchesQuery() { + + assertThat(template.query(Person.class).matching(query(where("firstname").is(luke.getFirstname()))).exists()) + .isTrue(); + } + + @Test // DATAMONGO-1734 + public void existsShouldReturnFalseWhenNoElementMatchesQuery() { + assertThat(template.query(Person.class).matching(query(where("firstname").is("spock"))).exists()).isFalse(); + } + @Data @org.springframework.data.mongodb.core.mapping.Document(collection = STAR_WARS) static class Person {