From 1290898c2b82ea53bc2ee68c36bec8ed6d229e6f Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Tue, 26 May 2020 14:07:58 +0200 Subject: [PATCH] DATAMONGO-2556 - Add estimatedCount for collections. The newly introduced methods delegate to the drivers MongoCollection.estimatedDocumentCount. Original pull request: #867. --- .../data/mongodb/core/MongoOperations.java | 23 ++++++++++++++++ .../data/mongodb/core/MongoTemplate.java | 13 ++++++++++ .../mongodb/core/ReactiveMongoOperations.java | 23 ++++++++++++++++ .../mongodb/core/ReactiveMongoTemplate.java | 26 ++++++++++++------- .../mongodb/core/MongoTemplateUnitTests.java | 10 +++++++ .../core/ReactiveMongoTemplateUnitTests.java | 10 +++++++ 6 files changed, 95 insertions(+), 10 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java index bb6c402fb..b1c5d3ee4 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java @@ -1184,6 +1184,29 @@ public interface MongoOperations extends FluentMongoOperations { */ long count(Query query, String collectionName); + /** + * Estimate the number of documents, in the collection {@link #getCollectionName(Class) identified by the given type}, + * based on collection statistics. + * + * @param entityClass must not be {@literal null}. + * @return the estimated number of documents. + * @since 3.1 + */ + default long estimatedCount(Class entityClass) { + + Assert.notNull(entityClass, "Entity class must not be null!"); + return estimatedCount(getCollectionName(entityClass)); + } + + /** + * Estimate the number of documents in the given collection based on collection statistics. + * + * @param collectionName must not be {@literal null}. + * @return the estimated number of documents. + * @since 3.1 + */ + long estimatedCount(String collectionName); + /** * Returns the number of documents for the given {@link Query} by querying the given collection using the given entity * class to map the given {@link Query}.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index d1f1790c7..91242611b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -1134,6 +1134,19 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, collection -> collection.countDocuments(CountQuery.of(filter).toQueryDocument(), options)); } + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.MongoOperations#estimatedCount(java.lang.String) + */ + @Override + public long estimatedCount(String collectionName) { + return doEstimatedCount(collectionName, new EstimatedDocumentCountOptions()); + } + + protected long doEstimatedCount(String collectionName, EstimatedDocumentCountOptions options) { + return execute(collectionName, collection -> collection.estimatedDocumentCount(options)); + } + /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.MongoOperations#insert(java.lang.Object) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java index 9bf4514b3..94fc8843f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java @@ -980,6 +980,29 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { */ Mono count(Query query, @Nullable Class entityClass, String collectionName); + /** + * Estimate the number of documents, in the collection {@link #getCollectionName(Class) identified by the given type}, + * based on collection statistics. + * + * @param entityClass must not be {@literal null}. + * @return a {@link Mono} emitting the estimated number of documents. + * @since 3.1 + */ + default Mono estimatedCount(Class entityClass) { + + Assert.notNull(entityClass, "Entity class must not be null!"); + return estimatedCount(getCollectionName(entityClass)); + } + + /** + * Estimate the number of documents in the given collection based on collection statistics. + * + * @param collectionName must not be {@literal null}. + * @return a {@link Mono} emitting the estimated number of documents. + * @since 3.1 + */ + Mono estimatedCount(String collectionName); + /** * Insert the object into the collection for the entity type of the object to save. *

diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java index 532ea54aa..336010434 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java @@ -17,6 +17,7 @@ package org.springframework.data.mongodb.core; import static org.springframework.data.mongodb.core.query.SerializationUtils.*; +import com.mongodb.client.model.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; @@ -116,16 +117,6 @@ import com.mongodb.CursorType; import com.mongodb.MongoException; import com.mongodb.ReadPreference; import com.mongodb.WriteConcern; -import com.mongodb.client.model.CountOptions; -import com.mongodb.client.model.CreateCollectionOptions; -import com.mongodb.client.model.DeleteOptions; -import com.mongodb.client.model.FindOneAndDeleteOptions; -import com.mongodb.client.model.FindOneAndReplaceOptions; -import com.mongodb.client.model.FindOneAndUpdateOptions; -import com.mongodb.client.model.ReplaceOptions; -import com.mongodb.client.model.ReturnDocument; -import com.mongodb.client.model.UpdateOptions; -import com.mongodb.client.model.ValidationOptions; import com.mongodb.client.model.changestream.FullDocument; import com.mongodb.client.result.DeleteResult; import com.mongodb.client.result.InsertOneResult; @@ -1247,6 +1238,15 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati }); } + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#estimatedCount(java.lang.String) + */ + @Override + public Mono estimatedCount(String collectionName) { + return doEstimatedCount(collectionName, new EstimatedDocumentCountOptions()); + } + /** * Run the actual count operation against the collection with given name. * @@ -1261,6 +1261,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati collection -> collection.countDocuments(CountQuery.of(filter).toQueryDocument(), options)); } + protected Mono doEstimatedCount(String collectionName, EstimatedDocumentCountOptions options) { + + return createMono(collectionName, + collection -> collection.estimatedDocumentCount(options)); + } + /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#insert(reactor.core.publisher.Mono) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java index 28f374d2b..f5cddf9d8 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java @@ -177,6 +177,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { when(collection.mapReduce(any(), any(), eq(Document.class))).thenReturn(mapReduceIterable); when(collection.countDocuments(any(Bson.class), any(CountOptions.class))).thenReturn(1L); // TODO: MongoDB 4 - fix // me + when(collection.estimatedDocumentCount(any())).thenReturn(1L); when(collection.getNamespace()).thenReturn(new MongoNamespace("db.mock-collection")); when(collection.aggregate(any(List.class), any())).thenReturn(aggregateIterable); when(collection.withReadPreference(any())).thenReturn(collection); @@ -2153,6 +2154,15 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { assertThat(saved.id).isEqualTo("after-save-event"); } + @Test // DATAMONGO-2556 + void esitmatedCountShouldBeDelegatedCorrectly() { + + template.estimatedCount(Person.class); + + verify(db).getCollection("star-wars", Document.class); + verify(collection).estimatedDocumentCount(any()); + } + class AutogenerateableId { @Id BigInteger id; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java index 46073a895..bd310e872 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java @@ -158,6 +158,7 @@ public class ReactiveMongoTemplateUnitTests { when(collection.aggregate(anyList())).thenReturn(aggregatePublisher); when(collection.aggregate(anyList(), any(Class.class))).thenReturn(aggregatePublisher); when(collection.countDocuments(any(), any(CountOptions.class))).thenReturn(Mono.just(0L)); + when(collection.estimatedDocumentCount(any())).thenReturn(Mono.just(0L)); when(collection.updateOne(any(), any(Bson.class), any(UpdateOptions.class))).thenReturn(updateResultPublisher); when(collection.updateMany(any(Bson.class), any(Bson.class), any())).thenReturn(updateResultPublisher); when(collection.updateOne(any(), anyList(), any())).thenReturn(updateResultPublisher); @@ -1365,6 +1366,15 @@ public class ReactiveMongoTemplateUnitTests { assertThat(saved.id).isEqualTo("after-save-event"); } + @Test // DATAMONGO-2556 + void esitmatedCountShouldBeDelegatedCorrectly() { + + template.estimatedCount(Person.class).subscribe(); + + verify(db).getCollection("star-wars", Document.class); + verify(collection).estimatedDocumentCount(any()); + } + private void stubFindSubscribe(Document document) { Publisher realPublisher = Flux.just(document);