Skip to content

Commit cd63501

Browse files
christophstroblmp911de
authored andcommitted
Support hints on Update.
This commit makes sure to read query hints and apply them to the MongoDB UpdateOptions when running an update via Reactive-/MongoTemplate. Original pull request: #4311 Closes: #3218
1 parent 0020499 commit cd63501

File tree

5 files changed

+63
-0
lines changed

5 files changed

+63
-0
lines changed

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

+18
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
* Function object to apply a query hint. Can be an index name or a BSON document.
2828
*
2929
* @author Mark Paluch
30+
* @author Christoph Strobl
3031
* @since 4.1
3132
*/
3233
class HintFunction {
@@ -67,6 +68,23 @@ public boolean isPresent() {
6768
return (hint instanceof String hintString && StringUtils.hasText(hintString)) || hint instanceof Bson;
6869
}
6970

71+
/**
72+
* Apply the hint to consumers depending on the hint format if {@link #isPresent() present}.
73+
*
74+
* @param registryProvider
75+
* @param stringConsumer
76+
* @param bsonConsumer
77+
* @param <R>
78+
*/
79+
public <R> void ifPresent(@Nullable CodecRegistryProvider registryProvider, Function<String, R> stringConsumer,
80+
Function<Bson, R> bsonConsumer) {
81+
82+
if (!isPresent()) {
83+
return;
84+
}
85+
apply(registryProvider, stringConsumer, bsonConsumer);
86+
}
87+
7088
/**
7189
* Apply the hint to consumers depending on the hint format.
7290
*

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

+1
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,7 @@ UpdateOptions getUpdateOptions(@Nullable Class<?> domainType, @Nullable Consumer
715715
.arrayFilters(update.getArrayFilters().stream().map(ArrayFilter::asDocument).collect(Collectors.toList()));
716716
}
717717

718+
HintFunction.from(getQuery().getHint()).ifPresent(codecRegistryProvider, options::hintString, options::hint);
718719
applyCollation(domainType, options::collation);
719720

720721
if (callback != null) {

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

+22
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,28 @@ void updateManyShouldUseCollationWhenPresent() {
978978
assertThat(options.getValue().getCollation().getLocale()).isEqualTo("fr");
979979
}
980980

981+
@Test // GH-3218
982+
void updateUsesHintStringFromQuery() {
983+
984+
template.updateFirst(new Query().withHint("index-1"), new Update().set("spring", "data"), Human.class);
985+
986+
ArgumentCaptor<UpdateOptions> options = ArgumentCaptor.forClass(UpdateOptions.class);
987+
verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture());
988+
989+
assertThat(options.getValue().getHintString()).isEqualTo("index-1");
990+
}
991+
992+
@Test // GH-3218
993+
void updateUsesHintDocumentFromQuery() {
994+
995+
template.updateFirst(new Query().withHint("{ name : 1 }"), new Update().set("spring", "data"), Human.class);
996+
997+
ArgumentCaptor<UpdateOptions> options = ArgumentCaptor.forClass(UpdateOptions.class);
998+
verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture());
999+
1000+
assertThat(options.getValue().getHint()).isEqualTo(new Document("name", 1));
1001+
}
1002+
9811003
@Test // DATAMONGO-1518
9821004
void replaceOneShouldUseCollationWhenPresent() {
9831005

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

+21
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,28 @@ void updateManyShouldUseCollationWhenPresent() {
350350
verify(collection).updateMany(any(), any(Bson.class), options.capture());
351351

352352
assertThat(options.getValue().getCollation().getLocale()).isEqualTo("fr");
353+
}
354+
355+
@Test // GH-3218
356+
void updateUsesHintStringFromQuery() {
357+
358+
template.updateFirst(new Query().withHint("index-1"), new Update().set("spring", "data"), Person.class).subscribe();
359+
360+
ArgumentCaptor<UpdateOptions> options = ArgumentCaptor.forClass(UpdateOptions.class);
361+
verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture());
362+
363+
assertThat(options.getValue().getHintString()).isEqualTo("index-1");
364+
}
365+
366+
@Test // GH-3218
367+
void updateUsesHintDocumentFromQuery() {
368+
369+
template.updateFirst(new Query().withHint("{ firstname : 1 }"), new Update().set("spring", "data"), Person.class).subscribe();
370+
371+
ArgumentCaptor<UpdateOptions> options = ArgumentCaptor.forClass(UpdateOptions.class);
372+
verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture());
353373

374+
assertThat(options.getValue().getHint()).isEqualTo(new Document("firstname", 1));
354375
}
355376

356377
@Test // DATAMONGO-1518

src/main/asciidoc/reference/mongodb.adoc

+1
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,7 @@ Most methods return the `Update` object to provide a fluent style for the API.
922922
* *updateMulti*: Updates all objects that match the query document criteria with the updated document.
923923

924924
WARNING: `updateFirst` does not support ordering. Please use <<mongo-template.find-and-upsert, findAndModify>> to apply `Sort`.
925+
NOTE: Index hints for the update operation can be provided via `Query.withHint(...)`.
925926

926927
[[mongodb-template-update.update]]
927928
==== Methods in the `Update` Class

0 commit comments

Comments
 (0)