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 b46f0f93c..1c41ec0c2 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 @@ -3558,7 +3558,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, Meta meta = query.getMeta(); HintFunction hintFunction = HintFunction.from(query.getHint()); - if (skip <= 0 && limit <= 0 && ObjectUtils.isEmpty(sortObject) && hintFunction.isEmpty() && !meta.hasValues() + if (skip <= 0 && limit <= 0 && ObjectUtils.isEmpty(sortObject) && hintFunction.isEmpty() && meta.isEmpty() && query.getCollation().isEmpty()) { return cursorToUse; } 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 e1ad78893..3fbe0d7fd 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 @@ -3419,7 +3419,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati HintFunction hintFunction = HintFunction.from(query.getHint()); Meta meta = query.getMeta(); - if (skip <= 0 && limit <= 0 && ObjectUtils.isEmpty(sortObject) && hintFunction.isEmpty() && !meta.hasValues()) { + if (skip <= 0 && limit <= 0 && ObjectUtils.isEmpty(sortObject) && hintFunction.isEmpty() && meta.isEmpty()) { return findPublisherToUse; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOptions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOptions.java index 16756fc91..1ac390942 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOptions.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOptions.java @@ -146,6 +146,8 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware private AggregationOptions(DiskUse diskUse, boolean explain, @Nullable Document cursor, @Nullable Collation collation, @Nullable String comment, @Nullable Object hint) { + Assert.notNull(diskUse, "DiskUse must not be null"); + this.diskUse = diskUse; this.explain = explain; this.cursor = Optional.ofNullable(cursor); @@ -442,7 +444,7 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware */ public static class Builder { - private @Nullable DiskUse diskUse = DiskUse.DEFAULT; + private DiskUse diskUse = DiskUse.DEFAULT; private boolean explain; private @Nullable Document cursor; private @Nullable Collation collation; @@ -470,10 +472,13 @@ public class AggregationOptions implements ReadConcernAware, ReadPreferenceAware * * @param diskUse use {@literal true} to allow disk use during the aggregation. * @return this. + * @since 5.0 */ @Contract("_ -> this") public Builder diskUse(DiskUse diskUse) { + Assert.notNull(diskUse, "DiskUse must not be null"); + this.diskUse = diskUse; return this; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/DiskUse.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/DiskUse.java index e2a60bb46..290fb61b6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/DiskUse.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/DiskUse.java @@ -15,31 +15,35 @@ */ package org.springframework.data.mongodb.core.query; +import java.util.Locale; + import org.jspecify.annotations.Nullable; import org.springframework.util.StringUtils; /** * Disk use indicates if the MongoDB server is allowed to write temporary files to disk during query/aggregation - * execution. MongoDB 6.0 server (and later) default for {@literal allowDiskUseByDefault} is {@literal true} on server - * side. + * execution. MongoDB 6.0 server (and later) default for {@literal allowDiskUseByDefault} is {@literal true} on the + * server side. * * @author Christoph Strobl * @since 5.0 + * @see com.mongodb.client.FindIterable#allowDiskUse(Boolean) + * @see com.mongodb.reactivestreams.client.FindPublisher#allowDiskUse(Boolean) */ public enum DiskUse { /** - * Go with the server default value and do not specify any override. + * Use the server default value and do not specify any override. */ DEFAULT, /** - * Override server default value and explicitly allow disk writes. + * Allow disk writes. */ ALLOW, /** - * Override server default value and explicitly deny disk writes. + * Explicitly deny disk writes. */ DENY; @@ -69,10 +73,10 @@ public enum DiskUse { return DEFAULT; } - return switch (value) { + return switch (value.toLowerCase(Locale.ROOT)) { case "true" -> ALLOW; case "false" -> DENY; - default -> valueOf(value.toUpperCase()); + default -> valueOf(value.toUpperCase(Locale.ROOT)); }; } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java index 530a030e9..225dfbd72 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java @@ -247,15 +247,33 @@ public class Meta { setDiskUse(DiskUse.of(allowDiskUse)); } + /** + * Sets the {@link DiskUse} to control whether temporary files are allowed to be written to disk during query. + * + * @param diskUse must not be {@literal null}. + * @since 5.0 + */ public void setDiskUse(DiskUse diskUse) { + + Assert.notNull(diskUse, "DiskUse must not be null"); + this.diskUse = diskUse; } /** - * @return + * @return {@literal true} there is at least one values, flags, cursor batch size, or disk use set; {@literal false} + * otherwise. */ public boolean hasValues() { - return !this.values.isEmpty() || !this.flags.isEmpty() || this.cursorBatchSize != null || !this.diskUse.equals(DiskUse.DEFAULT); + return !isEmpty(); + } + + /** + * @return {@literal true} if no values, flags, cursor batch size and disk use are set; {@literal false} otherwise. + */ + public boolean isEmpty() { + return this.values.isEmpty() && this.flags.isEmpty() && this.cursorBatchSize == null + && this.diskUse.equals(DiskUse.DEFAULT); } /** @@ -303,6 +321,8 @@ public class Meta { int hash = ObjectUtils.nullSafeHashCode(this.values); hash += ObjectUtils.nullSafeHashCode(this.flags); + hash += ObjectUtils.nullSafeHashCode(this.cursorBatchSize); + hash += ObjectUtils.nullSafeHashCode(this.diskUse); return hash; } @@ -320,7 +340,16 @@ public class Meta { if (!ObjectUtils.nullSafeEquals(this.values, other.values)) { return false; } - return ObjectUtils.nullSafeEquals(this.flags, other.flags); + + if (!ObjectUtils.nullSafeEquals(this.flags, other.flags)) { + return false; + } + + if (!ObjectUtils.nullSafeEquals(this.cursorBatchSize, other.cursorBatchSize)) { + return false; + } + + return ObjectUtils.nullSafeEquals(this.diskUse, other.diskUse); } /** diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java index 8a1572de9..6442842f7 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java @@ -15,9 +15,8 @@ */ package org.springframework.data.mongodb.core.query; -import static org.springframework.data.mongodb.core.query.SerializationUtils.serializeToJsonSafely; -import static org.springframework.util.ObjectUtils.nullSafeEquals; -import static org.springframework.util.ObjectUtils.nullSafeHashCode; +import static org.springframework.data.mongodb.core.query.SerializationUtils.*; +import static org.springframework.util.ObjectUtils.*; import java.time.Duration; import java.util.ArrayList; @@ -32,6 +31,7 @@ import java.util.Set; import org.bson.Document; import org.jspecify.annotations.Nullable; + import org.springframework.data.domain.KeysetScrollPosition; import org.springframework.data.domain.Limit; import org.springframework.data.domain.OffsetScrollPosition; @@ -585,6 +585,17 @@ public class Query implements ReadConcernAware, ReadPreferenceAware { return diskUse(DiskUse.of(allowDiskUse)); } + /** + * Configures writing to temporary files for aggregation stages and queries. When set to {@link DiskUse#ALLOW}, + * aggregation stages can write data to the {@code _tmp} subdirectory in the {@code dbPath} directory. + *
+ * Note that the default value for {@literal allowDiskUseByDefault} is {@literal true} on the server side since
+ * MongoDB 6.0.
+ *
+ * @param diskUse
+ * @return this.
+ * @since 5.0
+ */
@Contract("_ -> this")
public Query diskUse(DiskUse diskUse) {
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/QueryBlocks.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/QueryBlocks.java
index 79e716cf1..a1b86ab01 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/QueryBlocks.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/aot/QueryBlocks.java
@@ -239,14 +239,16 @@ class QueryBlocks {
if (StringUtils.hasText(source.getQuery().getFieldsString())) {
VariableSnippet fields = Snippet.declare(builder).variable(Document.class, context.localVariable("fields"))
- .of(MongoCodeBlocks.asDocument(context.getExpressionMarker(), source.getQuery().getFieldsString(), queryParameters.get()));
+ .of(MongoCodeBlocks.asDocument(context.getExpressionMarker(), source.getQuery().getFieldsString(),
+ queryParameters.get()));
builder.addStatement("$L.setFieldsObject($L)", queryVariableName, fields.getVariableName());
}
if (StringUtils.hasText(source.getQuery().getSortString())) {
VariableSnippet sort = Snippet.declare(builder).variable(Document.class, context.localVariable("sort"))
- .of(MongoCodeBlocks.asDocument(context.getExpressionMarker(), source.getQuery().getSortString(), getQueryParameters()));
+ .of(MongoCodeBlocks.asDocument(context.getExpressionMarker(), source.getQuery().getSortString(),
+ getQueryParameters()));
builder.addStatement("$L.setSortObject($L)", queryVariableName, sort.getVariableName());
}
@@ -312,13 +314,11 @@ class QueryBlocks {
} else {
if (getQueryParameters().isEmpty()) {
- builder.addStatement(
- "$L.collation(collationOf(evaluate($L, $S)))",
- queryVariableName, context.getExpressionMarker().enclosingMethod(), collationString);
+ builder.addStatement("$L.collation(collationOf(evaluate($L, $S)))", queryVariableName,
+ context.getExpressionMarker().enclosingMethod(), collationString);
} else {
- builder.addStatement(
- "$L.collation(collationOf(evaluate($L, $S, $L)))",
- queryVariableName, context.getExpressionMarker().enclosingMethod(), collationString, getQueryParameters());
+ builder.addStatement("$L.collation(collationOf(evaluate($L, $S, $L)))", queryVariableName,
+ context.getExpressionMarker().enclosingMethod(), collationString, getQueryParameters());
}
}
}
@@ -346,7 +346,8 @@ class QueryBlocks {
if (getQueryParameters().isEmpty()) {
builder.add("createQuery($L, $S)", context.getExpressionMarker().enclosingMethod(), source);
} else {
- builder.add("createQuery($L, $S, $L)", context.getExpressionMarker().enclosingMethod(), source, getQueryParameters());
+ builder.add("createQuery($L, $S, $L)", context.getExpressionMarker().enclosingMethod(), source,
+ getQueryParameters());
}
return builder.build();
} else {
diff --git a/src/main/antora/modules/ROOT/pages/mongodb/aot.adoc b/src/main/antora/modules/ROOT/pages/mongodb/aot.adoc
index 991581c8e..7a2e5f28d 100644
--- a/src/main/antora/modules/ROOT/pages/mongodb/aot.adoc
+++ b/src/main/antora/modules/ROOT/pages/mongodb/aot.adoc
@@ -76,7 +76,7 @@ These are typically all query methods that are not backed by an xref:repositorie
**Limitations**
-* `@Meta.allowDiskUse` and `flags` are not evaluated.
+* `@Meta.flags` is not evaluated.
* Limited `Collation` detection.
* No support for in-clauses with pattern matching / case insensitivity
diff --git a/src/main/antora/modules/ROOT/pages/mongodb/repositories/query-methods.adoc b/src/main/antora/modules/ROOT/pages/mongodb/repositories/query-methods.adoc
index 31a19b5ac..8ae506515 100644
--- a/src/main/antora/modules/ROOT/pages/mongodb/repositories/query-methods.adoc
+++ b/src/main/antora/modules/ROOT/pages/mongodb/repositories/query-methods.adoc
@@ -672,7 +672,7 @@ Use the `@Meta` annotation to set those options via `maxExecutionTimeMs`, `comme
----
interface PersonRepository extends CrudRepository