Skip to content

Accept index names as hint for aggregations. #4243

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.x-GH-4238-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data MongoDB</name>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-benchmarks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.x-GH-4238-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.x-GH-4238-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.x-GH-4238-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import org.apache.commons.logging.LogFactory;
import org.bson.Document;
import org.bson.conversions.Bson;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
Expand Down Expand Up @@ -634,15 +633,17 @@ public MongoCollection<Document> createCollection(String collectionName,
}

@Override
public MongoCollection<Document> createView(String name, Class<?> source, AggregationPipeline pipeline, @Nullable ViewOptions options) {
public MongoCollection<Document> createView(String name, Class<?> source, AggregationPipeline pipeline,
@Nullable ViewOptions options) {

return createView(name, getCollectionName(source),
queryOperations.createAggregation(Aggregation.newAggregation(source, pipeline.getOperations()), source),
options);
}

@Override
public MongoCollection<Document> createView(String name, String source, AggregationPipeline pipeline, @Nullable ViewOptions options) {
public MongoCollection<Document> createView(String name, String source, AggregationPipeline pipeline,
@Nullable ViewOptions options) {

return createView(name, source,
queryOperations.createAggregation(Aggregation.newAggregation(pipeline.getOperations()), (Class<?>) null),
Expand All @@ -654,7 +655,8 @@ private MongoCollection<Document> createView(String name, String source, Aggrega
return doCreateView(name, source, aggregation.getAggregationPipeline(), options);
}

protected MongoCollection<Document> doCreateView(String name, String source, List<Document> pipeline, @Nullable ViewOptions options) {
protected MongoCollection<Document> doCreateView(String name, String source, List<Document> pipeline,
@Nullable ViewOptions options) {

CreateViewOptions viewOptions = new CreateViewOptions();
if (options != null) {
Expand Down Expand Up @@ -2065,7 +2067,16 @@ protected <O> AggregationResults<O> doAggregate(Aggregation aggregation, String
}

options.getComment().ifPresent(aggregateIterable::comment);
options.getHint().ifPresent(aggregateIterable::hint);
if (options.getHintObject().isPresent()) {
Object hintObject = options.getHintObject().get();
if (hintObject instanceof String hintString) {
aggregateIterable = aggregateIterable.hintString(hintString);
} else if (hintObject instanceof Document hintDocument) {
aggregateIterable = aggregateIterable.hint(hintDocument);
} else {
throw new IllegalStateException("Unable to read hint of type %s".formatted(hintObject.getClass()));
}
}

if (options.hasExecutionTimeLimit()) {
aggregateIterable = aggregateIterable.maxTime(options.getMaxTime().toMillis(), TimeUnit.MILLISECONDS);
Expand Down Expand Up @@ -2124,7 +2135,16 @@ protected <O> Stream<O> aggregateStream(Aggregation aggregation, String collecti
}

options.getComment().ifPresent(cursor::comment);
options.getHint().ifPresent(cursor::hint);
if (options.getHintObject().isPresent()) {
Object hintObject = options.getHintObject().get();
if (hintObject instanceof String hintString) {
cursor = cursor.hintString(hintString);
} else if (hintObject instanceof Document hintDocument) {
cursor = cursor.hint(hintDocument);
} else {
throw new IllegalStateException("Unable to read hint of type %s".formatted(hintObject.getClass()));
}
}

Class<?> domainType = aggregation instanceof TypedAggregation ? ((TypedAggregation) aggregation).getInputType()
: null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,16 @@ private <O> Flux<O> aggregateAndMap(MongoCollection<Document> collection, List<D
}

options.getComment().ifPresent(cursor::comment);
options.getHint().ifPresent(cursor::hint);
if (options.getHintObject().isPresent()) {
Object hintObject = options.getHintObject().get();
if (hintObject instanceof String hintString) {
cursor = cursor.hintString(hintString);
} else if (hintObject instanceof Document hintDocument) {
cursor = cursor.hint(hintDocument);
} else {
throw new IllegalStateException("Unable to read hint of type %s".formatted(hintObject.getClass()));
}
}

Optionals.firstNonEmpty(options::getCollation, () -> operations.forType(inputType).getCollation()) //
.map(Collation::toMongoCollation) //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.bson.Document;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.util.BsonUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

Expand Down Expand Up @@ -53,7 +54,7 @@ public class AggregationOptions {
private final Optional<Document> cursor;
private final Optional<Collation> collation;
private final Optional<String> comment;
private final Optional<Document> hint;
private final Optional<Object> hint;
private Duration maxTime = Duration.ZERO;
private ResultOptions resultOptions = ResultOptions.READ;
private DomainTypeMapping domainTypeMapping = DomainTypeMapping.RELAXED;
Expand Down Expand Up @@ -113,7 +114,7 @@ public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Docum
* @since 3.1
*/
private AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Document cursor,
@Nullable Collation collation, @Nullable String comment, @Nullable Document hint) {
@Nullable Collation collation, @Nullable String comment, @Nullable Object hint) {

this.allowDiskUse = allowDiskUse;
this.explain = explain;
Expand Down Expand Up @@ -242,6 +243,44 @@ public Optional<String> getComment() {
* @since 3.1
*/
public Optional<Document> getHint() {
return hint.map(it -> {
if (it instanceof Document doc) {
return doc;
}
if (it instanceof String hintString) {
if (BsonUtils.isJsonDocument(hintString)) {
return BsonUtils.parse(hintString, null);
}
}
throw new IllegalStateException("Unable to read hint of type %s".formatted(it.getClass()));
});
}

/**
* Get the hint (indexName) used to to fulfill the aggregation.
*
* @return never {@literal null}.
* @since 4.1
*/
public Optional<String> getHintAsString() {
return hint.map(it -> {
if (it instanceof String hintString) {
return hintString;
}
if (it instanceof Document doc) {
return BsonUtils.toJson(doc);
}
throw new IllegalStateException("Unable to read hint of type %s".formatted(it.getClass()));
});
}

/**
* Get the hint used to to fulfill the aggregation.
*
* @return never {@literal null}.
* @since 4.1
*/
public Optional<Object> getHintObject() {
return hint;
}

Expand Down Expand Up @@ -361,7 +400,7 @@ public static class Builder {
private @Nullable Document cursor;
private @Nullable Collation collation;
private @Nullable String comment;
private @Nullable Document hint;
private @Nullable Object hint;
private @Nullable Duration maxTime;
private @Nullable ResultOptions resultOptions;
private @Nullable DomainTypeMapping domainTypeMapping;
Expand Down Expand Up @@ -454,6 +493,19 @@ public Builder hint(@Nullable Document hint) {
return this;
}

/**
* Define a hint that is used by query optimizer to to fulfill the aggregation.
*
* @param indexName can be {@literal null}.
* @return this.
* @since 4.1
*/
public Builder hint(@Nullable String indexName) {

this.hint = indexName;
return this;
}

/**
* Set the time limit for processing.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ void beforeEach() {
when(aggregateIterable.map(any())).thenReturn(aggregateIterable);
when(aggregateIterable.maxTime(anyLong(), any())).thenReturn(aggregateIterable);
when(aggregateIterable.into(any())).thenReturn(Collections.emptyList());
when(aggregateIterable.hint(any())).thenReturn(aggregateIterable);
when(aggregateIterable.hintString(any())).thenReturn(aggregateIterable);
when(distinctIterable.collation(any())).thenReturn(distinctIterable);
when(distinctIterable.map(any())).thenReturn(distinctIterable);
when(distinctIterable.into(any())).thenReturn(Collections.emptyList());
Expand Down Expand Up @@ -497,6 +499,16 @@ void aggregateShouldHonorOptionsHint() {
verify(aggregateIterable).hint(hint);
}

@Test // GH-4238
void aggregateShouldHonorOptionsHintString() {

AggregationOptions options = AggregationOptions.builder().hint("index-1").build();

template.aggregate(newAggregation(Aggregation.unwind("foo")).withOptions(options), "collection-1", Wrapper.class);

verify(aggregateIterable).hintString("index-1");
}

@Test // GH-3542
void aggregateShouldUseRelaxedMappingByDefault() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.mongodb.core.MongoTemplateUnitTests.Wrapper;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
Expand Down Expand Up @@ -666,6 +668,17 @@ void aggregateShouldHonorOptionsHint() {
verify(aggregatePublisher).hint(hint);
}

@Test // GH-4238
void aggregateShouldHonorOptionsHintString() {

AggregationOptions options = AggregationOptions.builder().hint("index-1").build();

template.aggregate(newAggregation(Sith.class, project("id")).withOptions(options), AutogenerateableId.class,
Document.class).subscribe();

verify(aggregatePublisher).hintString("index-1");
}

@Test // DATAMONGO-2390
void aggregateShouldNoApplyZeroOrNegativeMaxTime() {

Expand Down