Skip to content

Commit 22bd3e6

Browse files
thekaleidoscopemp911de
authored andcommitted
DATAMONGO-1836 - Add support to hint in aggregation options.
Original pull request: #878.
1 parent 6e47d5c commit 22bd3e6

File tree

6 files changed

+93
-8
lines changed

6 files changed

+93
-8
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java

+5
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
* @author Cimon Lucas
156156
* @author Michael J. Simons
157157
* @author Roman Puchkovskiy
158+
* @author Yadhukrishna S Pai
158159
*/
159160
public class MongoTemplate implements MongoOperations, ApplicationContextAware, IndexOperationsProvider {
160161

@@ -2149,6 +2150,8 @@ protected <O> AggregationResults<O> doAggregate(Aggregation aggregation, String
21492150

21502151
options.getComment().ifPresent(aggregateIterable::comment);
21512152

2153+
options.getHint().ifPresent(aggregateIterable::hint);
2154+
21522155
if (options.hasExecutionTimeLimit()) {
21532156
aggregateIterable = aggregateIterable.maxTime(options.getMaxTime().toMillis(), TimeUnit.MILLISECONDS);
21542157
}
@@ -2207,6 +2210,8 @@ protected <O> CloseableIterator<O> aggregateStream(Aggregation aggregation, Stri
22072210

22082211
options.getComment().ifPresent(cursor::comment);
22092212

2213+
options.getHint().ifPresent(cursor::hint);
2214+
22102215
Class<?> domainType = aggregation instanceof TypedAggregation ? ((TypedAggregation) aggregation).getInputType()
22112216
: null;
22122217

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java

+3
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
* @author Christoph Strobl
147147
* @author Roman Puchkovskiy
148148
* @author Mathieu Ouellet
149+
* @author Yadhukrishna S Pai
149150
* @since 2.0
150151
*/
151152
public class ReactiveMongoTemplate implements ReactiveMongoOperations, ApplicationContextAware {
@@ -1024,6 +1025,8 @@ private <O> Flux<O> aggregateAndMap(MongoCollection<Document> collection, List<D
10241025

10251026
options.getComment().ifPresent(cursor::comment);
10261027

1028+
options.getHint().ifPresent(cursor::hint);
1029+
10271030
Optionals.firstNonEmpty(options::getCollation, () -> operations.forType(inputType).getCollation()) //
10281031
.map(Collation::toMongoCollation) //
10291032
.ifPresent(cursor::collation);

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOptions.java

+45-4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
* @author Oliver Gierke
3333
* @author Christoph Strobl
3434
* @author Mark Paluch
35+
* @author Yadhukrishna S Pai
3536
* @see Aggregation#withOptions(AggregationOptions)
3637
* @see TypedAggregation#withOptions(AggregationOptions)
3738
* @since 1.6
@@ -45,12 +46,14 @@ public class AggregationOptions {
4546
private static final String COLLATION = "collation";
4647
private static final String COMMENT = "comment";
4748
private static final String MAX_TIME = "maxTimeMS";
49+
private static final String HINT = "hint";
4850

4951
private final boolean allowDiskUse;
5052
private final boolean explain;
5153
private final Optional<Document> cursor;
5254
private final Optional<Collation> collation;
5355
private final Optional<String> comment;
56+
private final Optional<Document> hint;
5457
private Duration maxTime = Duration.ZERO;
5558
private ResultOptions resultOptions = ResultOptions.READ;
5659

@@ -77,7 +80,7 @@ public AggregationOptions(boolean allowDiskUse, boolean explain, Document cursor
7780
*/
7881
public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Document cursor,
7982
@Nullable Collation collation) {
80-
this(allowDiskUse, explain, cursor, collation, null);
83+
this(allowDiskUse, explain, cursor, collation, null, null);
8184
}
8285

8386
/**
@@ -89,16 +92,18 @@ public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Docum
8992
* aggregation.
9093
* @param collation collation for string comparison. Can be {@literal null}.
9194
* @param comment execution comment. Can be {@literal null}.
95+
* @param hint can be {@literal null}, used to provide an index that would be forcibly used by query optimizer.
9296
* @since 2.2
9397
*/
9498
public AggregationOptions(boolean allowDiskUse, boolean explain, @Nullable Document cursor,
95-
@Nullable Collation collation, @Nullable String comment) {
99+
@Nullable Collation collation, @Nullable String comment, @Nullable Document hint) {
96100

97101
this.allowDiskUse = allowDiskUse;
98102
this.explain = explain;
99103
this.cursor = Optional.ofNullable(cursor);
100104
this.collation = Optional.ofNullable(collation);
101105
this.comment = Optional.ofNullable(comment);
106+
this.hint = Optional.ofNullable(hint);
102107
}
103108

104109
/**
@@ -130,8 +135,9 @@ public static AggregationOptions fromDocument(Document document) {
130135
Collation collation = document.containsKey(COLLATION) ? Collation.from(document.get(COLLATION, Document.class))
131136
: null;
132137
String comment = document.getString(COMMENT);
138+
Document hint = document.get(HINT, Document.class);
133139

134-
AggregationOptions options = new AggregationOptions(allowDiskUse, explain, cursor, collation, comment);
140+
AggregationOptions options = new AggregationOptions(allowDiskUse, explain, cursor, collation, comment, hint);
135141
if (document.containsKey(MAX_TIME)) {
136142
options.maxTime = Duration.ofMillis(document.getLong(MAX_TIME));
137143
}
@@ -212,6 +218,16 @@ public Optional<String> getComment() {
212218
return comment;
213219
}
214220

221+
/**
222+
* Get the hint used to to fulfill the aggregation.
223+
*
224+
* @return never {@literal null}.
225+
*/
226+
public Optional<Document> getHint() {
227+
return hint;
228+
}
229+
230+
215231
/**
216232
* @return the time limit for processing. {@link Duration#ZERO} is used for the default unbounded behavior.
217233
* @since 3.0
@@ -248,6 +264,10 @@ Document applyAndReturnPotentiallyChangedCommand(Document command) {
248264
result.put(EXPLAIN, explain);
249265
}
250266

267+
if (result.containsKey(HINT)) {
268+
hint.ifPresent(val -> result.append(HINT, val));
269+
}
270+
251271
if (!result.containsKey(CURSOR)) {
252272
cursor.ifPresent(val -> result.put(CURSOR, val));
253273
}
@@ -277,6 +297,7 @@ public Document toDocument() {
277297
cursor.ifPresent(val -> document.put(CURSOR, val));
278298
collation.ifPresent(val -> document.append(COLLATION, val.toDocument()));
279299
comment.ifPresent(val -> document.append(COMMENT, val));
300+
hint.ifPresent(val -> document.append(HINT, val));
280301

281302
if (hasExecutionTimeLimit()) {
282303
document.append(MAX_TIME, maxTime.toMillis());
@@ -318,6 +339,7 @@ public static class Builder {
318339
private @Nullable Document cursor;
319340
private @Nullable Collation collation;
320341
private @Nullable String comment;
342+
private @Nullable Document hint;
321343
private @Nullable Duration maxTime;
322344
private @Nullable ResultOptions resultOptions;
323345

@@ -396,6 +418,19 @@ public Builder comment(@Nullable String comment) {
396418
return this;
397419
}
398420

421+
/**
422+
* Define a hint is used forcibly by query optimizer to to fulfill the aggregation.
423+
*
424+
* @param hint can be {@literal null}.
425+
* @return this.
426+
* @since 2.2
427+
*/
428+
public Builder hint(@Nullable Document hint) {
429+
430+
this.hint = hint;
431+
return this;
432+
}
433+
399434
/**
400435
* Set the time limit for processing.
401436
*
@@ -431,7 +466,13 @@ public Builder skipOutput() {
431466
*/
432467
public AggregationOptions build() {
433468

434-
AggregationOptions options = new AggregationOptions(allowDiskUse, explain, cursor, collation, comment);
469+
AggregationOptions options = new AggregationOptions(
470+
allowDiskUse,
471+
explain,
472+
cursor,
473+
collation,
474+
comment,
475+
hint);
435476
if (maxTime != null) {
436477
options.maxTime = maxTime;
437478
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java

+12
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
* @author Mark Paluch
140140
* @author Michael J. Simons
141141
* @author Roman Puchkovskiy
142+
* @author Yadhukrishna S Pai
142143
*/
143144
@MockitoSettings(strictness = Strictness.LENIENT)
144145
public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
@@ -468,6 +469,17 @@ void aggregateShouldHonorOptionsComment() {
468469
verify(aggregateIterable).comment("expensive");
469470
}
470471

472+
@Test // DATAMONGO-1836
473+
void aggregateShouldHonorOptionsHint() {
474+
475+
Document hint = new Document("dummyField", 1);
476+
AggregationOptions options = AggregationOptions.builder().hint(hint).build();
477+
478+
template.aggregate(newAggregation(Aggregation.unwind("foo")).withOptions(options), "collection-1", Wrapper.class);
479+
480+
verify(aggregateIterable).hint(hint);
481+
}
482+
471483
@Test // DATAMONGO-1166, DATAMONGO-2264
472484
void geoNearShouldHonorReadPreferenceWhenSet() {
473485

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java

+12
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
* @author Christoph Strobl
118118
* @author Roman Puchkovskiy
119119
* @author Mathieu Ouellet
120+
* @author Yadhukrishna S Pai
120121
*/
121122
@ExtendWith(MockitoExtension.class)
122123
@MockitoSettings(strictness = Strictness.LENIENT)
@@ -628,6 +629,17 @@ void aggregateShouldHonorOptionsComment() {
628629
verify(aggregatePublisher).comment("expensive");
629630
}
630631

632+
@Test // DATAMONGO-1836
633+
void aggregateShouldHonorOptionsHint() {
634+
Document hint = new Document("dummyHint", 1);
635+
AggregationOptions options = AggregationOptions.builder().hint(hint).build();
636+
637+
template.aggregate(newAggregation(Sith.class, project("id")).withOptions(options), AutogenerateableId.class,
638+
Document.class).subscribe();
639+
640+
verify(aggregatePublisher).hint(hint);
641+
}
642+
631643
@Test // DATAMONGO-2390
632644
void aggregateShouldNoApplyZeroOrNegativeMaxTime() {
633645

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationOptionsTests.java

+16-4
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
2828
* @author Thomas Darimont
2929
* @author Mark Paluch
3030
* @author Christoph Strobl
31+
* @author Yadhukrishna S Pai
3132
* @since 1.6
3233
*/
3334
public class AggregationOptionsTests {
3435

36+
private final Document dummyHint = new Document("dummyField", 1);
3537
AggregationOptions aggregationOptions;
3638

3739
@BeforeEach
@@ -40,25 +42,28 @@ public void setup() {
4042
.cursorBatchSize(1) //
4143
.allowDiskUse(true) //
4244
.comment("hola!") //
45+
.hint(dummyHint) //
4346
.build();
4447
}
4548

46-
@Test // DATAMONGO-960
49+
@Test // DATAMONGO-960, DATAMONGO-1836
4750
public void aggregationOptionsBuilderShouldSetOptionsAccordingly() {
4851

4952
assertThat(aggregationOptions.isAllowDiskUse()).isTrue();
5053
assertThat(aggregationOptions.isExplain()).isTrue();
5154
assertThat(aggregationOptions.getCursor().get()).isEqualTo(new Document("batchSize", 1));
55+
assertThat(aggregationOptions.getHint().get()).isEqualTo(dummyHint);
5256
}
5357

54-
@Test // DATAMONGO-1637, DATAMONGO-2153
58+
@Test // DATAMONGO-1637, DATAMONGO-2153, DATAMONGO-1836
5559
public void shouldInitializeFromDocument() {
5660

5761
Document document = new Document();
5862
document.put("cursor", new Document("batchSize", 1));
5963
document.put("explain", true);
6064
document.put("allowDiskUse", true);
6165
document.put("comment", "hola!");
66+
document.put("hint", dummyHint);
6267

6368
aggregationOptions = AggregationOptions.fromDocument(document);
6469

@@ -67,12 +72,19 @@ public void shouldInitializeFromDocument() {
6772
assertThat(aggregationOptions.getCursor().get()).isEqualTo(new Document("batchSize", 1));
6873
assertThat(aggregationOptions.getCursorBatchSize()).isEqualTo(1);
6974
assertThat(aggregationOptions.getComment().get()).isEqualTo("hola!");
75+
assertThat(aggregationOptions.getHint().get()).isEqualTo(dummyHint);
7076
}
7177

72-
@Test // DATAMONGO-960, DATAMONGO-2153
78+
@Test // DATAMONGO-960, DATAMONGO-2153, DATAMONGO-1836
7379
public void aggregationOptionsToString() {
7480

7581
assertThat(aggregationOptions.toDocument()).isEqualTo(Document.parse(
76-
"{ \"allowDiskUse\" : true , \"explain\" : true , \"cursor\" : { \"batchSize\" : 1}, \"comment\": \"hola!\"}"));
82+
"{ " +
83+
"\"allowDiskUse\" : true , " +
84+
"\"explain\" : true , " +
85+
"\"cursor\" : { \"batchSize\" : 1}, " +
86+
"\"comment\": \"hola!\", " +
87+
"\"hint\" : { \"dummyField\" : 1}" +
88+
"}"));
7789
}
7890
}

0 commit comments

Comments
 (0)