DATAMONGO-2449 - Evaluate allowDiskUse added to Meta annotation when executing derived Aggregation.

@Meta(allowDiskUse...) allows to set the according aggregation option when executing a String based annotation via a repository definition.

Original pull request: #827.
This commit is contained in:
Christoph Strobl
2020-01-07 09:01:24 +01:00
committed by Mark Paluch
parent f8ee9648da
commit 85519eb84d
6 changed files with 83 additions and 6 deletions

View File

@@ -52,6 +52,7 @@ public class Meta {
private final Map<String, Object> values = new LinkedHashMap<>(2);
private final Set<CursorOption> flags = new LinkedHashSet<>();
private Integer cursorBatchSize;
private Boolean allowDiskUse;
public Meta() {}
@@ -65,6 +66,7 @@ public class Meta {
this.values.putAll(source.values);
this.flags.addAll(source.flags);
this.cursorBatchSize = source.cursorBatchSize;
this.allowDiskUse = source.allowDiskUse;
}
/**
@@ -245,6 +247,27 @@ public class Meta {
return ObjectUtils.nullSafeEquals(this.flags, other.flags);
}
/**
* When set to true, aggregation stages can write data to disk.
*
* @return {@literal null} if not set.
* @since 3.0
*/
@Nullable
public Boolean getAllowDiskUse() {
return allowDiskUse;
}
/**
* Set to true, to allow aggregation stages to write data to disk.
*
* @param allowDiskUse use {@literal null} for server defaults.
* @since 3.0
*/
public void setAllowDiskUse(@Nullable Boolean allowDiskUse) {
this.allowDiskUse = allowDiskUse;
}
/**
* {@link CursorOption} represents {@code OP_QUERY} wire protocol flags to change the behavior of queries.
*

View File

@@ -67,4 +67,13 @@ public @interface Meta {
*/
org.springframework.data.mongodb.core.query.Meta.CursorOption[] flags() default {};
/**
* When set to true, aggregation stages can write data to disk.
*
* @return {@literal false} by default.
* @since 3.0
* @see Aggregation
*/
boolean allowDiskUse() default false;
}

View File

@@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.query;
import lombok.experimental.UtilityClass;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -93,6 +94,14 @@ class AggregationUtils {
builder.cursorBatchSize(meta.getCursorBatchSize());
}
if(meta.getMaxTimeMsec() != null && meta.getMaxTimeMsec() > 0) {
builder.maxTime(Duration.ofMillis(meta.getMaxTimeMsec()));
}
if (meta.getAllowDiskUse() != null) {
builder.allowDiskUse(meta.getAllowDiskUse());
}
return builder;
}

View File

@@ -293,6 +293,10 @@ public class MongoQueryMethod extends QueryMethod {
}
}
if(meta.allowDiskUse()) {
metaAttributes.setAllowDiskUse(meta.allowDiskUse());
}
return metaAttributes;
}

View File

@@ -22,6 +22,7 @@ import static org.mockito.Mockito.*;
import lombok.Value;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -33,7 +34,6 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoOperations;
@@ -102,18 +102,19 @@ public class StringBasedAggregationUnitTests {
assertThat(pipelineOf(invocation)).containsExactly(GROUP_BY_LASTNAME, SORT);
}
@Test // DATAMONGO-2153
@Test // DATAMONGO-2153, DATAMONGO-2449
public void plainStringAggregationConsidersMeta() {
AggregationInvocation invocation = executeAggregation("plainStringAggregation");
AggregationOptions options = invocation.aggregation.getOptions();
assertThat(options.getComment()).contains("expensive-aggregation");
assertThat(options.getCursorBatchSize()).isEqualTo(42);
assertThat(options.isAllowDiskUse()).isTrue();
assertThat(options.getMaxTime()).isEqualTo(Duration.ofMillis(100));
}
@Test // DATAMONGO-2153
@Test // DATAMONGO-2153, DATAMONGO-2449
public void returnSingleObject() {
PersonAggregate expected = new PersonAggregate();
@@ -126,6 +127,8 @@ public class StringBasedAggregationUnitTests {
assertThat(options.getComment()).isEmpty();
assertThat(options.getCursorBatchSize()).isNull();
assertThat(options.isAllowDiskUse()).isFalse();
assertThat(options.getMaxTime()).isEqualTo(Duration.ZERO);
}
@Test // DATAMONGO-2153
@@ -246,7 +249,7 @@ public class StringBasedAggregationUnitTests {
private interface SampleRepository extends Repository<Person, Long> {
@Meta(cursorBatchSize = 42, comment = "expensive-aggregation")
@Meta(cursorBatchSize = 42, comment = "expensive-aggregation", allowDiskUse = true, maxExecutionTimeMs = 100)
@Aggregation({ RAW_GROUP_BY_LASTNAME_STRING, RAW_SORT_STRING })
PersonAggregate plainStringAggregation();

View File

@@ -11,7 +11,6 @@ The definition may contain simple placeholders like `?0` as well as https://docs
----
public interface PersonRepository extends CrudReppsitory<Person, String> {
@Aggregation("{ $group: { _id : $lastname, names : { $addToSet : $firstname } } }")
List<PersonAggregate> groupByLastnameAndFirstnames(); <1>
@@ -74,6 +73,36 @@ To gain more control, you might consider `AggregationResult` as method return ty
<8> Like in <6>, a single value can be directly obtained from multiple result ``Document``s.
====
In some scenarios aggregations might require additional options like a maximum execution time, additional log comments or the permission to temporarily write data to disk.
Use the `@Meta` annotation to set those options via `maxExecutionTimeMs`, `comment` or `allowDiskUse`.
[source,java]
----
public interface PersonRepository extends CrudReppsitory<Person, String> {
@Meta(allowDiskUse = true)
@Aggregation("{ $group: { _id : $lastname, names : { $addToSet : $firstname } } }")
List<PersonAggregate> groupByLastnameAndFirstnames();
}
----
Or use `@Meta` to create your own annotation as shown in the sample below.
[source,java]
----
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
@Meta(allowDiskUse = true)
@interface AllowDiskUse { }
public interface PersonRepository extends CrudReppsitory<Person, String> {
@AllowDiskUse
@Aggregation("{ $group: { _id : $lastname, names : { $addToSet : $firstname } } }")
List<PersonAggregate> groupByLastnameAndFirstnames();
}
----
TIP: You can use `@Aggregation` also with <<mongo.reactive.repositories, Reactive Repositories>>.
[NOTE]