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 0e5feea19..f889e95c7 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 @@ -57,8 +57,7 @@ import com.mongodb.client.result.UpdateResult; /** * Interface that specifies a basic set of MongoDB operations. Implemented by {@link MongoTemplate}. Not often used but * a useful option for extensibility and testability (as it can be easily mocked, stubbed, or be the target of a JDK - * proxy). - *
+ * proxy).
* NOTE: Some operations cannot be executed within a MongoDB transaction. Please refer to the MongoDB * specific documentation to learn more about Multi * Document Transactions. @@ -84,7 +83,7 @@ public interface MongoOperations extends FluentMongoOperations { String getCollectionName(Class entityClass); /** - * Execute the a MongoDB command expressed as a JSON string. Parsing is delegated to {@link Document#parse(String)} to + * Execute a MongoDB command expressed as a JSON string. Parsing is delegated to {@link Document#parse(String)} to * obtain the {@link Document} holding the actual command. Any errors that result from executing this command will be * converted into Spring's DAO exception hierarchy. * @@ -124,8 +123,7 @@ public interface MongoOperations extends FluentMongoOperations { void executeQuery(Query query, String collectionName, DocumentCallbackHandler dch); /** - * Executes a {@link DbCallback} translating any exceptions as necessary. - *
+ * Executes a {@link DbCallback} translating any exceptions as necessary.
* Allows for returning a result object, that is a domain object or a collection of domain objects. * * @param action callback object that specifies the MongoDB actions to perform on the passed in DB instance. Must not @@ -137,8 +135,7 @@ public interface MongoOperations extends FluentMongoOperations { T execute(DbCallback action); /** - * Executes the given {@link CollectionCallback} on the entity collection of the specified class. - *
+ * Executes the given {@link CollectionCallback} on the entity collection of the specified class.
* Allows for returning a result object, that is a domain object or a collection of domain objects. * * @param entityClass class that determines the collection to use. Must not be {@literal null}. @@ -150,8 +147,7 @@ public interface MongoOperations extends FluentMongoOperations { T execute(Class entityClass, CollectionCallback action); /** - * Executes the given {@link CollectionCallback} on the collection of the given name. - *
+ * Executes the given {@link CollectionCallback} on the collection of the given name.
* Allows for returning a result object, that is a domain object or a collection of domain objects. * * @param collectionName the name of the collection that specifies which {@link MongoCollection} instance will be @@ -175,8 +171,7 @@ public interface MongoOperations extends FluentMongoOperations { /** * Obtain a {@link ClientSession session} bound instance of {@link SessionScoped} binding the {@link ClientSession} - * provided by the given {@link Supplier} to each and every command issued against MongoDB. - *
+ * provided by the given {@link Supplier} to each and every command issued against MongoDB.
* Note: It is up to the caller to manage the {@link ClientSession} lifecycle. Use the * {@link SessionScoped#execute(SessionCallback, Consumer)} hook to potentially close the {@link ClientSession}. * @@ -211,8 +206,7 @@ public interface MongoOperations extends FluentMongoOperations { } /** - * Obtain a {@link ClientSession} bound instance of {@link MongoOperations}. - *
+ * Obtain a {@link ClientSession} bound instance of {@link MongoOperations}.
* Note: It is up to the caller to manage the {@link ClientSession} lifecycle. * * @param session must not be {@literal null}. @@ -299,8 +293,7 @@ public interface MongoOperations extends FluentMongoOperations { * Get a {@link MongoCollection} by its name. The returned collection may not exists yet (except in local memory) and * is created on first interaction with the server. Collections can be explicitly created via * {@link #createCollection(Class)}. Please make sure to check if the collection {@link #collectionExists(Class) - * exists} first. - *
+ * exists} first.
* Translate any exceptions as necessary. * * @param collectionName name of the collection. Must not be {@literal null}. @@ -309,8 +302,7 @@ public interface MongoOperations extends FluentMongoOperations { MongoCollection getCollection(String collectionName); /** - * Check to see if a collection with a name indicated by the entity class exists. - *
+ * Check to see if a collection with a name indicated by the entity class exists.
* Translate any exceptions as necessary. * * @param entityClass class that determines the name of the collection. Must not be {@literal null}. @@ -319,8 +311,7 @@ public interface MongoOperations extends FluentMongoOperations { boolean collectionExists(Class entityClass); /** - * Check to see if a collection with a given name exists. - *
+ * Check to see if a collection with a given name exists.
* Translate any exceptions as necessary. * * @param collectionName name of the collection. Must not be {@literal null}. @@ -329,8 +320,7 @@ public interface MongoOperations extends FluentMongoOperations { boolean collectionExists(String collectionName); /** - * Drop the collection with the name indicated by the entity class. - *
+ * Drop the collection with the name indicated by the entity class.
* Translate any exceptions as necessary. * * @param entityClass class that determines the collection to drop/delete. Must not be {@literal null}. @@ -338,8 +328,7 @@ public interface MongoOperations extends FluentMongoOperations { void dropCollection(Class entityClass); /** - * Drop the collection with the given name. - *
+ * Drop the collection with the given name.
* Translate any exceptions as necessary. * * @param collectionName name of the collection to drop/delete. @@ -402,11 +391,9 @@ public interface MongoOperations extends FluentMongoOperations { BulkOperations bulkOps(BulkMode mode, @Nullable Class entityType, String collectionName); /** - * Query for a list of objects of type T from the collection used by the entity class. - *
+ * Query for a list of objects of type T from the collection used by the entity class.
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way * to map objects since the test for class type is done in the client and not on the server. * @@ -416,11 +403,9 @@ public interface MongoOperations extends FluentMongoOperations { List findAll(Class entityClass); /** - * Query for a list of objects of type T from the specified collection. - *
+ * Query for a list of objects of type T from the specified collection.
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* If your collection does not contain a homogeneous collection of types, this operation will not be an efficient way * to map objects since the test for class type is done in the client and not on the server. * @@ -538,12 +523,10 @@ public interface MongoOperations extends FluentMongoOperations { CloseableIterator aggregateStream(TypedAggregation aggregation, String collectionName, Class outputType); /** - * Execute an aggregation operation backed by a Mongo DB {@link com.mongodb.client.AggregateIterable}. - *
+ * Execute an aggregation operation backed by a Mongo DB {@link com.mongodb.client.AggregateIterable}.
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.client.AggregateIterable} that * needs to be closed. The raw results will be mapped to the given entity class and are returned as stream. The name - * of the inputCollection is derived from the inputType of the aggregation. - *
+ * of the inputCollection is derived from the inputType of the aggregation.
* Aggregation streaming can't be used with {@link AggregationOptions#isExplain() aggregation explain}. Enabling * explanation mode will throw an {@link IllegalArgumentException}. * @@ -556,11 +539,9 @@ public interface MongoOperations extends FluentMongoOperations { CloseableIterator aggregateStream(TypedAggregation aggregation, Class outputType); /** - * Execute an aggregation operation backed by a Mongo DB {@link com.mongodb.client.AggregateIterable}. - *
+ * Execute an aggregation operation backed by a Mongo DB {@link com.mongodb.client.AggregateIterable}.
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.client.AggregateIterable} that - * needs to be closed. The raw results will be mapped to the given entity class. - *
+ * needs to be closed. The raw results will be mapped to the given entity class.
* Aggregation streaming can't be used with {@link AggregationOptions#isExplain() aggregation explain}. Enabling * explanation mode will throw an {@link IllegalArgumentException}. * @@ -575,11 +556,9 @@ public interface MongoOperations extends FluentMongoOperations { CloseableIterator aggregateStream(Aggregation aggregation, Class inputType, Class outputType); /** - * Execute an aggregation operation backed by a Mongo DB {@link com.mongodb.client.AggregateIterable}. - *
+ * Execute an aggregation operation backed by a Mongo DB {@link com.mongodb.client.AggregateIterable}.
* Returns a {@link CloseableIterator} that wraps the a Mongo DB {@link com.mongodb.client.AggregateIterable} that - * needs to be closed. The raw results will be mapped to the given entity class. - *
+ * needs to be closed. The raw results will be mapped to the given entity class.
* Aggregation streaming can't be used with {@link AggregationOptions#isExplain() aggregation explain}. Enabling * explanation mode will throw an {@link IllegalArgumentException}. * @@ -709,11 +688,9 @@ public interface MongoOperations extends FluentMongoOperations { /** * Map the results of an ad-hoc query on the collection for the entity class to a single instance of an object of the - * specified type. - *
+ * specified type.
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more * feature rich {@link Query}. * @@ -727,11 +704,9 @@ public interface MongoOperations extends FluentMongoOperations { /** * Map the results of an ad-hoc query on the specified collection to a single instance of an object of the specified - * type. - *
+ * type.
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more * feature rich {@link Query}. * @@ -775,11 +750,9 @@ public interface MongoOperations extends FluentMongoOperations { boolean exists(Query query, @Nullable Class entityClass, String collectionName); /** - * Map the results of an ad-hoc query on the collection for the entity class to a List of the specified type. - *
+ * Map the results of an ad-hoc query on the collection for the entity class to a List of the specified type.
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more * feature rich {@link Query}. * @@ -791,11 +764,9 @@ public interface MongoOperations extends FluentMongoOperations { List find(Query query, Class entityClass); /** - * Map the results of an ad-hoc query on the specified collection to a List of the specified type. - *
+ * Map the results of an ad-hoc query on the specified collection to a List of the specified type.
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more * feature rich {@link Query}. * @@ -1127,10 +1098,8 @@ public interface MongoOperations extends FluentMongoOperations { /** * Map the results of an ad-hoc query on the collection for the entity type to a single instance of an object of the * specified type. The first document that matches the query is returned and also removed from the collection in the - * database. - *
- * The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. - *
+ * database.
+ * The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}.
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more * feature rich {@link Query}. * @@ -1147,8 +1116,7 @@ public interface MongoOperations extends FluentMongoOperations { * type. The first document that matches the query is returned and also removed from the collection in the database. *
* The object is converted from the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* The query is specified as a {@link Query} which can be created either using the {@link BasicQuery} or the more * feature rich {@link Query}. * @@ -1167,8 +1135,96 @@ public interface MongoOperations extends FluentMongoOperations { * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct * influence on the resulting number of documents found as those values are passed on to the server and potentially * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. + * count all matches.
+ * This method may choose to use {@link #estimatedCount(Class)} for empty queries instead of running an + * {@link com.mongodb.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) + * aggregation execution} which may have an impact on performance. + * + * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be + * {@literal null}. + * @param entityClass class that determines the collection to use. Must not be {@literal null}. + * @return the count of matching documents. + * @see #exactCount(Query, Class) + * @see #estimatedCount(Class) + */ + long count(Query query, Class entityClass); + + /** + * Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query} + * must solely consist of document field references as we lack type information to map potential property references + * onto document fields. Use {@link #count(Query, Class, String)} to get full type specific support.
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches.
+ * This method may choose to use {@link #estimatedCount(Class)} for empty queries instead of running an + * {@link com.mongodb.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) + * aggregation execution} which may have an impact on performance. + * + * @param query the {@link Query} class that specifies the criteria used to find documents. + * @param collectionName must not be {@literal null} or empty. + * @return the count of matching documents. + * @see #count(Query, Class, String) + * @see #exactCount(Query, String) + * @see #estimatedCount(String) + */ + long count(Query query, 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}.
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches.
+ * This method may choose to use {@link #estimatedCount(Class)} for empty queries instead of running an + * {@link com.mongodb.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) + * aggregation execution} which may have an impact on performance. + * + * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be + * {@literal null}. + * @param entityClass the parametrized type. Can be {@literal null}. + * @param collectionName must not be {@literal null} or empty. + * @return the count of matching documents. + * @see #count(Query, Class, String) + * @see #estimatedCount(String) + */ + long 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.
+ * Please make sure to read the MongoDB reference documentation about limitations on eg. sharded cluster or inside + * transactions. + * + * @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.
+ * Please make sure to read the MongoDB reference documentation about limitations on eg. sharded cluster or inside + * transactions. + * + * @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 collection of the given entity class. *
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches.
* This method uses an * {@link com.mongodb.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) * aggregation execution} even for empty {@link Query queries} which may have an impact on performance, but guarantees @@ -1192,8 +1248,7 @@ public interface MongoOperations extends FluentMongoOperations { * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct * influence on the resulting number of documents found as those values are passed on to the server and potentially * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
+ * count all matches.
* This method uses an * {@link com.mongodb.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) * aggregation execution} even for empty {@link Query queries} which may have an impact on performance, but guarantees @@ -1216,8 +1271,7 @@ public interface MongoOperations extends FluentMongoOperations { * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct * influence on the resulting number of documents found as those values are passed on to the server and potentially * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
+ * count all matches.
* This method uses an * {@link com.mongodb.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) * aggregation execution} even for empty {@link Query queries} which may have an impact on performance, but guarantees @@ -1234,104 +1288,13 @@ public interface MongoOperations extends FluentMongoOperations { long exactCount(Query query, @Nullable Class entityClass, String collectionName); /** - * Returns the number of documents for the given {@link Query} by querying the collection of the given entity class. - *
- * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct - * influence on the resulting number of documents found as those values are passed on to the server and potentially - * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
- * This method may choose to use {@link #estimatedCount(Class)} for empty queries instead of running an - * {@link com.mongodb.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) - * aggregation execution} which may have an impact on performance. - * - * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be - * {@literal null}. - * @param entityClass class that determines the collection to use. Must not be {@literal null}. - * @return the count of matching documents. - */ - long count(Query query, Class entityClass); - - /** - * Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query} - * must solely consist of document field references as we lack type information to map potential property references - * onto document fields. Use {@link #count(Query, Class, String)} to get full type specific support.
- * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct - * influence on the resulting number of documents found as those values are passed on to the server and potentially - * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
- * This method may choose to use {@link #estimatedCount(Class)} for empty queries instead of running an - * {@link com.mongodb.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) - * aggregation execution} which may have an impact on performance. - * - * @param query the {@link Query} class that specifies the criteria used to find documents. - * @param collectionName must not be {@literal null} or empty. - * @return the count of matching documents. - * @see #count(Query, Class, String) - */ - 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. - *
- * Please make sure to read the MongoDB reference documentation about limitations on eg. sharded cluster or inside - * transactions. - * - * @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. - *
- * Please make sure to read the MongoDB reference documentation about limitations on eg. sharded cluster or inside - * transactions. - * - * @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}.
- * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct - * influence on the resulting number of documents found as those values are passed on to the server and potentially - * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
- * This method may choose to use {@link #estimatedCount(Class)} for empty queries instead of running an - * {@link com.mongodb.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) - * aggregation execution} which may have an impact on performance. - * - * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be - * {@literal null}. - * @param entityClass the parametrized type. Can be {@literal null}. - * @param collectionName must not be {@literal null} or empty. - * @return the count of matching documents. - */ - long count(Query query, @Nullable Class entityClass, String collectionName); - - /** - * Insert the object into the collection for the entity type of the object to save. - *
- * The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. - *
+ * Insert the object into the collection for the entity type of the object to save.
+ * The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}.
* If your object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a * String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your * property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See * Spring's - * Type Conversion" for more details. - *
+ * Type Conversion" for more details.
* Insert is used to initially store the object into the database. To update an existing object use the save method. *
* The {@code objectToSave} must not be collection-like. @@ -1343,11 +1306,9 @@ public interface MongoOperations extends FluentMongoOperations { T insert(T objectToSave); /** - * Insert the object into the specified collection. - *
+ * Insert the object into the specified collection.
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* Insert is used to initially store the object into the database. To update an existing object use the save method. *
* The {@code objectToSave} must not be collection-like. @@ -1388,17 +1349,14 @@ public interface MongoOperations extends FluentMongoOperations { /** * Save the object to the collection for the entity type of the object to save. This will perform an insert if the - * object is not already present, that is an 'upsert'. - *
+ * object is not already present, that is an 'upsert'.
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* If your object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a * String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your * property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See * Spring's - * Type Conversion" for more details. - *
+ * Type Conversion" for more details.
* The {@code objectToSave} must not be collection-like. * * @param objectToSave the object to store in the collection. Must not be {@literal null}. @@ -1409,16 +1367,14 @@ public interface MongoOperations extends FluentMongoOperations { /** * Save the object to the specified collection. This will perform an insert if the object is not already present, that - * is an 'upsert'. - *
+ * is an 'upsert'.
* The object is converted to the MongoDB native representation using an instance of {@see MongoConverter}. Unless - * configured otherwise, an instance of {@link MappingMongoConverter} will be used. - *
+ * configured otherwise, an instance of {@link MappingMongoConverter} will be used.
* If your object has an "Id' property, it will be set with the generated Id from MongoDB. If your Id property is a * String then MongoDB ObjectId will be used to populate that string. Otherwise, the conversion from ObjectId to your - * property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. - * See Spring's Type Conversion for more details. - *
+ * property type will be handled by Spring's BeanWrapper class that leverages Type Conversion API. See + * Spring's Type + * Conversion for more details.
* The {@code objectToSave} must not be collection-like. * * @param objectToSave the object to store in the collection. Must not be {@literal null}. 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 b8bac461d..b95f9b38b 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 @@ -348,10 +348,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, } /** - * En-/Disable usage of estimated count. + * Configure whether to use estimated count. Defaults to exact counting. * - * @param enabled if {@literal true} {@link MongoCollection#estimatedDocumentCount()} ()} will we used for unpaged, - * empty {@link Query queries}. + * @param enabled use {@link com.mongodb.client.MongoCollection#estimatedDocumentCount()} for unpaged and empty + * {@link Query queries} if {@code true}. * @since 3.4 */ public void useEstimatedCount(boolean enabled) { @@ -359,10 +359,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, } /** - * En-/Disable usage of estimated count based on the given {@link BiPredicate estimationFilter}. + * Configure whether to use estimated count based on the given {@link BiPredicate estimationFilter}. * - * @param enabled if {@literal true} {@link MongoCollection#estimatedDocumentCount()} will we used for {@link Document - * filter queries} that pass the given {@link BiPredicate estimationFilter}. + * @param enabled use {@link com.mongodb.client.MongoCollection#estimatedDocumentCount()} for unpaged and empty + * {@link Query queries} if {@code true}. * @param estimationFilter the {@link BiPredicate filter}. * @since 3.4 */ @@ -453,8 +453,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, MongoPersistentEntity persistentEntity = mappingContext.getPersistentEntity(entityType); QueryContext queryContext = queryOperations.createQueryContext(query); - EntityProjection projection = operations.introspectProjection(returnType, - entityType); + EntityProjection projection = operations.introspectProjection(returnType, entityType); Document mappedQuery = queryContext.getMappedQuery(persistentEntity); Document mappedFields = queryContext.getMappedFields(persistentEntity, projection); @@ -1003,8 +1002,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, .withOptions(AggregationOptions.builder().collation(near.getCollation()).build()); AggregationResults results = aggregate($geoNear, collection, Document.class); - EntityProjection projection = operations.introspectProjection(returnType, - domainType); + EntityProjection projection = operations.introspectProjection(returnType, domainType); DocumentCallback> callback = new GeoNearResultDocumentCallback<>(distanceField, new ProjectingReadCallback<>(mongoConverter, projection, collection), near.getMetric()); @@ -1091,8 +1089,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityType); QueryContext queryContext = queryOperations.createQueryContext(query); - EntityProjection projection = operations.introspectProjection(resultType, - entityType); + EntityProjection projection = operations.introspectProjection(resultType, entityType); Document mappedQuery = queryContext.getMappedQuery(entity); Document mappedFields = queryContext.getMappedFields(entity, projection); Document mappedSort = queryContext.getMappedSort(entity); @@ -1104,8 +1101,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, maybeCallBeforeSave(replacement, mappedReplacement, collectionName); T saved = doFindAndReplace(collectionName, mappedQuery, mappedFields, mappedSort, - queryContext.getCollation(entityType).orElse(null), entityType, mappedReplacement, options, - projection); + queryContext.getCollation(entityType).orElse(null), entityType, mappedReplacement, options, projection); if (saved != null) { maybeEmitEvent(new AfterSaveEvent<>(saved, mappedReplacement, collectionName)); @@ -1149,17 +1145,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return count(query, null, collectionName); } - @Override - public long exactCount(Query query, @Nullable Class entityClass, String collectionName) { - - CountContext countContext = queryOperations.countQueryContext(query); - - CountOptions options = countContext.getCountOptions(entityClass); - Document mappedQuery = countContext.getMappedQuery(entityClass, mappingContext::getPersistentEntity); - - return doExactCount(collectionName, mappedQuery, options); - } - /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.MongoOperations#count(org.springframework.data.mongodb.core.query.Query, java.lang.Class, java.lang.String) @@ -1177,7 +1162,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return doCount(collectionName, mappedQuery, options); } - @SuppressWarnings("ConstantConditions") protected long doCount(String collectionName, Document filter, CountOptions options) { if (LOGGER.isDebugEnabled()) { @@ -1188,6 +1172,30 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return countExecution.countDocuments(collectionName, filter, 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)); + } + + @Override + public long exactCount(Query query, @Nullable Class entityClass, String collectionName) { + + CountContext countContext = queryOperations.countQueryContext(query); + + CountOptions options = countContext.getCountOptions(entityClass); + Document mappedQuery = countContext.getMappedQuery(entityClass, mappingContext::getPersistentEntity); + + return doExactCount(collectionName, mappedQuery, options); + } + protected long doExactCount(String collectionName, Document filter, CountOptions options) { return execute(collectionName, collection -> collection.countDocuments(CountQuery.of(filter).toQueryDocument(), options)); @@ -1208,19 +1216,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, return options.getLimit() <= 0 && options.getSkip() <= 0; } - /* - * (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) @@ -2575,8 +2570,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); QueryContext queryContext = queryOperations.createQueryContext(new BasicQuery(query, fields)); - Document mappedFields = queryContext.getMappedFields(entity, - EntityProjection.nonProjecting(entityClass)); + Document mappedFields = queryContext.getMappedFields(entity, EntityProjection.nonProjecting(entityClass)); Document mappedQuery = queryContext.getMappedQuery(entity); if (LOGGER.isDebugEnabled()) { @@ -2628,8 +2622,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); QueryContext queryContext = queryOperations.createQueryContext(new BasicQuery(query, fields)); - Document mappedFields = queryContext.getMappedFields(entity, - EntityProjection.nonProjecting(entityClass)); + Document mappedFields = queryContext.getMappedFields(entity, EntityProjection.nonProjecting(entityClass)); Document mappedQuery = queryContext.getMappedQuery(entity); if (LOGGER.isDebugEnabled()) { @@ -2651,8 +2644,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Class targetClass, CursorPreparer preparer) { MongoPersistentEntity entity = mappingContext.getPersistentEntity(sourceClass); - EntityProjection projection = operations.introspectProjection(targetClass, - sourceClass); + EntityProjection projection = operations.introspectProjection(targetClass, sourceClass); QueryContext queryContext = queryOperations.createQueryContext(new BasicQuery(query, fields)); Document mappedFields = queryContext.getMappedFields(entity, projection); @@ -2667,7 +2659,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, new ProjectingReadCallback<>(mongoConverter, projection, collectionName), collectionName); } - /** * Convert given {@link CollectionOptions} to a document and take the domain type information into account when * creating a mapped schema for validation.
@@ -2747,8 +2738,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, /** * Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter. - * The first document that matches the query is returned and also removed from the collection in the database. - *
+ * The first document that matches the query is returned and also removed from the collection in the database.
* The query document is specified as a standard Document and so is the fields specification. * * @param collectionName name of the collection to retrieve the objects from @@ -2826,8 +2816,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Document mappedSort, @Nullable com.mongodb.client.model.Collation collation, Class entityType, Document replacement, FindAndReplaceOptions options, Class resultType) { - EntityProjection projection = operations.introspectProjection(resultType, - entityType); + EntityProjection projection = operations.introspectProjection(resultType, entityType); return doFindAndReplace(collectionName, mappedQuery, mappedFields, mappedSort, collation, entityType, replacement, options, projection); @@ -2855,10 +2844,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Document replacement, FindAndReplaceOptions options, EntityProjection projection) { if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format( - "findAndReplace using query: %s fields: %s sort: %s for class: %s and replacement: %s " + "in collection: %s", - serializeToJsonSafely(mappedQuery), serializeToJsonSafely(mappedFields), serializeToJsonSafely(mappedSort), - entityType, serializeToJsonSafely(replacement), collectionName)); + LOGGER + .debug(String.format( + "findAndReplace using query: %s fields: %s sort: %s for class: %s and replacement: %s " + + "in collection: %s", + serializeToJsonSafely(mappedQuery), serializeToJsonSafely(mappedFields), + serializeToJsonSafely(mappedSort), entityType, serializeToJsonSafely(replacement), collectionName)); } return executeFindOneInternal( @@ -3051,8 +3042,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("findOne using query: %s fields: %s in db.collection: %s", - serializeToJsonSafely(query), - serializeToJsonSafely(fields.orElseGet(Document::new)), + serializeToJsonSafely(query), serializeToJsonSafely(fields.orElseGet(Document::new)), collection.getNamespace() != null ? collection.getNamespace().getFullName() : "n/a")); } @@ -3318,8 +3308,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, private final EntityProjection projection; private final String collectionName; - ProjectingReadCallback(MongoConverter mongoConverter, EntityProjection projection, - String collectionName) { + ProjectingReadCallback(MongoConverter mongoConverter, EntityProjection projection, String collectionName) { this.mongoConverter = mongoConverter; this.projection = projection; @@ -3598,8 +3587,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, /** * {@link MongoTemplate} extension bound to a specific {@link ClientSession} that is applied when interacting with the - * server through the driver API. - *
+ * server through the driver API.
* The prepare steps for {@link MongoDatabase} and {@link MongoCollection} proxy the target and invoke the desired * target method matching the actual arguments plus a {@link ClientSession}. * 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 d50355dac..1bde11633 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 @@ -91,7 +91,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { ReactiveIndexOperations indexOps(Class entityClass); /** - * Execute the a MongoDB command expressed as a JSON string. This will call the method JSON.parse that is part of the + * Execute a MongoDB command expressed as a JSON string. This will call the method JSON.parse that is part of the * MongoDB driver to convert the JSON string to a Document. Any errors that result from executing this command will be * converted into Spring's DAO exception hierarchy. * @@ -939,80 +939,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct * influence on the resulting number of documents found as those values are passed on to the server and potentially * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
- * This method uses an - * {@link com.mongodb.reactivestreams.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) - * aggregation execution} even for empty {@link Query queries} which may have an impact on performance, but guarantees - * shard, session and transaction compliance. In case an inaccurate count satisfies the applications needs use - * {@link #estimatedCount(Class)} for empty queries instead. - * - * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be - * {@literal null}. - * @param entityClass class that determines the collection to use. Must not be {@literal null}. - * @return the count of matching documents. - * @since 3.4 - */ - default Mono exactCount(Query query, Class entityClass) { - return exactCount(query, entityClass, getCollectionName(entityClass)); - } - - /** - * Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query} - * must solely consist of document field references as we lack type information to map potential property references - * onto document fields. Use {@link #count(Query, Class, String)} to get full type specific support.
- * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct - * influence on the resulting number of documents found as those values are passed on to the server and potentially - * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
- * This method uses an - * {@link com.mongodb.reactivestreams.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) - * aggregation execution} even for empty {@link Query queries} which may have an impact on performance, but guarantees - * shard, session and transaction compliance. In case an inaccurate count satisfies the applications needs use - * {@link #estimatedCount(String)} for empty queries instead. - * - * @param query the {@link Query} class that specifies the criteria used to find documents. - * @param collectionName must not be {@literal null} or empty. - * @return the count of matching documents. - * @see #count(Query, Class, String) - * @since 3.4 - */ - default Mono exactCount(Query query, String collectionName) { - return exactCount(query, null, 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}.
- * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct - * influence on the resulting number of documents found as those values are passed on to the server and potentially - * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
- * This method uses an - * {@link com.mongodb.reactivestreams.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) - * aggregation execution} even for empty {@link Query queries} which may have an impact on performance, but guarantees - * shard, session and transaction compliance. In case an inaccurate count satisfies the applications needs use - * {@link #estimatedCount(String)} for empty queries instead. - * - * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be - * {@literal null}. - * @param entityClass the parametrized type. Can be {@literal null}. - * @param collectionName must not be {@literal null} or empty. - * @return the count of matching documents. - * @since 3.4 - */ - Mono exactCount(Query query, @Nullable Class entityClass, String collectionName); - - /** - * Returns the number of documents for the given {@link Query} by querying the collection of the given entity class. - *
- * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct - * influence on the resulting number of documents found as those values are passed on to the server and potentially - * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
+ * count all matches.
* This method may choose to use {@link #estimatedCount(Class)} for empty queries instead of running an * {@link com.mongodb.reactivestreams.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) * aggregation execution} which may have an impact on performance. @@ -1021,6 +948,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * {@literal null}. * @param entityClass class that determines the collection to use. Must not be {@literal null}. * @return the count of matching documents. + * @see #exactCount(Query, Class) + * @see #estimatedCount(Class) */ Mono count(Query query, Class entityClass); @@ -1031,8 +960,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct * influence on the resulting number of documents found as those values are passed on to the server and potentially * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
+ * count all matches.
* This method may choose to use {@link #estimatedCount(Class)} for empty queries instead of running an * {@link com.mongodb.reactivestreams.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) * aggregation execution} which may have an impact on performance. @@ -1041,6 +969,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @param collectionName must not be {@literal null} or empty. * @return the count of matching documents. * @see #count(Query, Class, String) + * @see #estimatedCount(String) + * @see #exactCount(Query, String) */ Mono count(Query query, String collectionName); @@ -1050,8 +980,7 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct * influence on the resulting number of documents found as those values are passed on to the server and potentially * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to - * count all matches. - *
+ * count all matches.
* This method may choose to use {@link #estimatedCount(Class)} for empty queries instead of running an * {@link com.mongodb.reactivestreams.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) * aggregation execution} which may have an impact on performance. @@ -1061,6 +990,8 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { * @param entityClass the parametrized type. Can be {@literal null}. * @param collectionName must not be {@literal null} or empty. * @return the count of matching documents. + * @see #estimatedCount(String) + * @see #exactCount(Query, Class, String) */ Mono count(Query query, @Nullable Class entityClass, String collectionName); @@ -1093,6 +1024,75 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { */ Mono estimatedCount(String collectionName); + /** + * Returns the number of documents for the given {@link Query} by querying the collection of the given entity class. + *
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches.
+ * This method uses an + * {@link com.mongodb.reactivestreams.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) + * aggregation execution} even for empty {@link Query queries} which may have an impact on performance, but guarantees + * shard, session and transaction compliance. In case an inaccurate count satisfies the applications needs use + * {@link #estimatedCount(Class)} for empty queries instead. + * + * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be + * {@literal null}. + * @param entityClass class that determines the collection to use. Must not be {@literal null}. + * @return the count of matching documents. + * @since 3.4 + */ + default Mono exactCount(Query query, Class entityClass) { + return exactCount(query, entityClass, getCollectionName(entityClass)); + } + + /** + * Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query} + * must solely consist of document field references as we lack type information to map potential property references + * onto document fields. Use {@link #count(Query, Class, String)} to get full type specific support.
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches.
+ * This method uses an + * {@link com.mongodb.reactivestreams.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) + * aggregation execution} even for empty {@link Query queries} which may have an impact on performance, but guarantees + * shard, session and transaction compliance. In case an inaccurate count satisfies the applications needs use + * {@link #estimatedCount(String)} for empty queries instead. + * + * @param query the {@link Query} class that specifies the criteria used to find documents. + * @param collectionName must not be {@literal null} or empty. + * @return the count of matching documents. + * @see #count(Query, Class, String) + * @since 3.4 + */ + default Mono exactCount(Query query, String collectionName) { + return exactCount(query, null, 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}.
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches.
+ * This method uses an + * {@link com.mongodb.reactivestreams.client.MongoCollection#countDocuments(org.bson.conversions.Bson, com.mongodb.client.model.CountOptions) + * aggregation execution} even for empty {@link Query queries} which may have an impact on performance, but guarantees + * shard, session and transaction compliance. In case an inaccurate count satisfies the applications needs use + * {@link #estimatedCount(String)} for empty queries instead. + * + * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be + * {@literal null}. + * @param entityClass the parametrized type. Can be {@literal null}. + * @param collectionName must not be {@literal null} or empty. + * @return the count of matching documents. + * @since 3.4 + */ + Mono exactCount(Query query, @Nullable Class entityClass, 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 49c6e075c..cfb3b9294 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,7 +17,6 @@ package org.springframework.data.mongodb.core; import static org.springframework.data.mongodb.core.query.SerializationUtils.*; -import org.springframework.data.projection.EntityProjection; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; @@ -34,6 +33,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; +import java.util.function.BiPredicate; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -115,6 +115,7 @@ import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter; import org.springframework.data.mongodb.core.timeseries.Granularity; import org.springframework.data.mongodb.core.validation.Validator; import org.springframework.data.mongodb.util.BsonUtils; +import org.springframework.data.projection.EntityProjection; import org.springframework.data.util.Optionals; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -358,8 +359,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati /** * Set the {@link ReactiveEntityCallbacks} instance to use when invoking * {@link org.springframework.data.mapping.callback.EntityCallback callbacks} like the - * {@link ReactiveBeforeSaveCallback}. - *
+ * {@link ReactiveBeforeSaveCallback}.
* Overrides potentially existing {@link ReactiveEntityCallbacks}. * * @param entityCallbacks must not be {@literal null}. @@ -373,10 +373,10 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati } /** - * En-/Disable usage of estimated count. + * Configure whether to use estimated count. Defaults to exact counting. * - * @param enabled if {@literal true} {@link com.mongodb.client.MongoCollection#estimatedDocumentCount()} ()} will we used for unpaged, - * empty {@link Query queries}. + * @param enabled use {@link com.mongodb.client.MongoCollection#estimatedDocumentCount()} for unpaged and empty + * {@link Query queries} if {@code true}. * @since 3.4 */ public void useEstimatedCount(boolean enabled) { @@ -384,11 +384,11 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati } /** - * En-/Disable usage of estimated count based on the given {@link BiFunction estimationFilter}. + * Configure whether to use estimated count based on the given {@link BiPredicate estimationFilter}. * - * @param enabled if {@literal true} {@link com.mongodb.client.MongoCollection#estimatedDocumentCount()} will we used for {@link Document - * filter queries} that pass the given {@link BiFunction estimationFilter}. - * @param estimationFilter the {@link BiFunction filter}. + * @param enabled use {@link com.mongodb.client.MongoCollection#estimatedDocumentCount()} for unpaged and empty + * {@link Query queries} if {@code true}. + * @param estimationFilter the {@link BiPredicate filter}. * @since 3.4 */ private void useEstimatedCount(boolean enabled, BiFunction> estimationFilter) { @@ -1098,8 +1098,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati String collection = StringUtils.hasText(collectionName) ? collectionName : getCollectionName(entityClass); String distanceField = operations.nearQueryDistanceFieldName(entityClass); - EntityProjection projection = operations.introspectProjection(returnType, - entityClass); + EntityProjection projection = operations.introspectProjection(returnType, entityClass); GeoNearResultDocumentCallback callback = new GeoNearResultDocumentCallback<>(distanceField, new ProjectingReadCallback<>(mongoConverter, projection, collection), near.getMetric()); @@ -1181,8 +1180,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityType); QueryContext queryContext = queryOperations.createQueryContext(query); - EntityProjection projection = operations.introspectProjection(resultType, - entityType); + EntityProjection projection = operations.introspectProjection(resultType, entityType); Document mappedQuery = queryContext.getMappedQuery(entity); Document mappedFields = queryContext.getMappedFields(entity, projection); @@ -1205,8 +1203,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati }).flatMap(it -> { Mono afterFindAndReplace = doFindAndReplace(it.getCollection(), mappedQuery, mappedFields, mappedSort, - queryContext.getCollation(entityType).orElse(null), entityType, it.getTarget(), options, - projection); + queryContext.getCollation(entityType).orElse(null), entityType, it.getTarget(), options, projection); return afterFindAndReplace.flatMap(saved -> { maybeEmitEvent(new AfterSaveEvent<>(saved, it.getTarget(), it.getCollection())); return maybeCallAfterSave(saved, it.getTarget(), it.getCollection()); @@ -1235,17 +1232,6 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati entityClass); } - @Override - public Mono exactCount(Query query, @Nullable Class entityClass, String collectionName) { - - CountContext countContext = queryOperations.countQueryContext(query); - - CountOptions options = countContext.getCountOptions(entityClass); - Document mappedQuery = countContext.getMappedQuery(entityClass, mappingContext::getPersistentEntity); - - return doExactCount(collectionName, mappedQuery, options); - } - /* * (non-Javadoc) * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#count(org.springframework.data.mongodb.core.query.Query, java.lang.Class) @@ -1290,15 +1276,6 @@ 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. * @@ -1317,19 +1294,39 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati return countExecution.countDocuments(collectionName, filter, options); } - protected Mono doExactCount(String collectionName, Document filter, CountOptions options) { - - return createMono(collectionName, - collection -> collection.countDocuments(CountQuery.of(filter).toQueryDocument(), options)); + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.ReactiveMongoOperations#estimatedCount(java.lang.String) + */ + @Override + public Mono estimatedCount(String collectionName) { + return doEstimatedCount(collectionName, new EstimatedDocumentCountOptions()); } protected Mono doEstimatedCount(String collectionName, EstimatedDocumentCountOptions options) { return createMono(collectionName, collection -> collection.estimatedDocumentCount(options)); } + @Override + public Mono exactCount(Query query, @Nullable Class entityClass, String collectionName) { + + CountContext countContext = queryOperations.countQueryContext(query); + + CountOptions options = countContext.getCountOptions(entityClass); + Document mappedQuery = countContext.getMappedQuery(entityClass, mappingContext::getPersistentEntity); + + return doExactCount(collectionName, mappedQuery, options); + } + + protected Mono doExactCount(String collectionName, Document filter, CountOptions options) { + + return createMono(collectionName, + collection -> collection.countDocuments(CountQuery.of(filter).toQueryDocument(), options)); + } + protected Mono countCanBeEstimated(Document filter, CountOptions options) { - if(!filter.isEmpty() || !isEmptyOptions(options)) { + if (!filter.isEmpty() || !isEmptyOptions(options)) { return Mono.just(false); } return ReactiveMongoDatabaseUtils.isTransactionActive(getMongoDatabaseFactory()).map(it -> !it); @@ -2450,8 +2447,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati QueryContext queryContext = queryOperations .createQueryContext(new BasicQuery(query, fields != null ? fields : new Document())); - Document mappedFields = queryContext.getMappedFields(entity, - EntityProjection.nonProjecting(entityClass)); + Document mappedFields = queryContext.getMappedFields(entity, EntityProjection.nonProjecting(entityClass)); Document mappedQuery = queryContext.getMappedQuery(entity); if (LOGGER.isDebugEnabled()) { @@ -2503,8 +2499,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati MongoPersistentEntity entity = mappingContext.getPersistentEntity(entityClass); QueryContext queryContext = queryOperations.createQueryContext(new BasicQuery(query, fields)); - Document mappedFields = queryContext.getMappedFields(entity, - EntityProjection.nonProjecting(entityClass)); + Document mappedFields = queryContext.getMappedFields(entity, EntityProjection.nonProjecting(entityClass)); Document mappedQuery = queryContext.getMappedQuery(entity); if (LOGGER.isDebugEnabled()) { @@ -2526,8 +2521,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati Class targetClass, FindPublisherPreparer preparer) { MongoPersistentEntity entity = mappingContext.getPersistentEntity(sourceClass); - EntityProjection projection = operations.introspectProjection(targetClass, - sourceClass); + EntityProjection projection = operations.introspectProjection(targetClass, sourceClass); QueryContext queryContext = queryOperations.createQueryContext(new BasicQuery(query, fields)); Document mappedFields = queryContext.getMappedFields(entity, projection); @@ -2602,8 +2596,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati /** * Map the results of an ad-hoc query on the default MongoDB collection to an object using the template's converter. - * The first document that matches the query is returned and also removed from the collection in the database. - *
+ * The first document that matches the query is returned and also removed from the collection in the database.
* The query document is specified as a standard Document and so is the fields specification. * * @param collectionName name of the collection to retrieve the objects from @@ -2674,8 +2667,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati Document mappedSort, com.mongodb.client.model.Collation collation, Class entityType, Document replacement, FindAndReplaceOptions options, Class resultType) { - EntityProjection projection = operations.introspectProjection(resultType, - entityType); + EntityProjection projection = operations.introspectProjection(resultType, entityType); return doFindAndReplace(collectionName, mappedQuery, mappedFields, mappedSort, collation, entityType, replacement, options, projection); @@ -3298,8 +3290,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati private final EntityProjection projection; private final String collectionName; - ProjectingReadCallback(MongoConverter reader, EntityProjection projection, - String collectionName) { + ProjectingReadCallback(MongoConverter reader, EntityProjection projection, String collectionName) { this.reader = reader; this.projection = projection; this.collectionName = collectionName; @@ -3476,8 +3467,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati /** * {@link MongoTemplate} extension bound to a specific {@link ClientSession} that is applied when interacting with the - * server through the driver API. - *
+ * server through the driver API.
* The prepare steps for {@link MongoDatabase} and {@link MongoCollection} proxy the target and invoke the desired * target method matching the actual arguments plus a {@link ClientSession}. *