diff --git a/pom.xml b/pom.xml index d864b2e4e6..b54ac65d06 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 4.1.0-SNAPSHOT + 4.1.x-GH-3218-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml index 1b2a1390e6..4dd1549a1a 100644 --- a/spring-data-mongodb-benchmarks/pom.xml +++ b/spring-data-mongodb-benchmarks/pom.xml @@ -7,7 +7,7 @@ org.springframework.data spring-data-mongodb-parent - 4.1.0-SNAPSHOT + 4.1.x-GH-3218-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 8db8d798fb..ed455a503b 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -15,7 +15,7 @@ org.springframework.data spring-data-mongodb-parent - 4.1.0-SNAPSHOT + 4.1.x-GH-3218-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 9a57f7eb52..597aebc0be 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -13,7 +13,7 @@ org.springframework.data spring-data-mongodb-parent - 4.1.0-SNAPSHOT + 4.1.x-GH-3218-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/HintFunction.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/HintFunction.java index c9b5514b28..c4e07f5b37 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/HintFunction.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/HintFunction.java @@ -27,6 +27,7 @@ * Function object to apply a query hint. Can be an index name or a BSON document. * * @author Mark Paluch + * @author Christoph Strobl * @since 4.1 */ class HintFunction { @@ -67,6 +68,23 @@ public boolean isPresent() { return (hint instanceof String hintString && StringUtils.hasText(hintString)) || hint instanceof Bson; } + /** + * Apply the hint to consumers depending on the hint format if {@link #isPresent() present}. + * + * @param registryProvider + * @param stringConsumer + * @param bsonConsumer + * @param + */ + public void ifPresent(@Nullable CodecRegistryProvider registryProvider, Function stringConsumer, + Function bsonConsumer) { + + if (!isPresent()) { + return; + } + apply(registryProvider, stringConsumer, bsonConsumer); + } + /** * Apply the hint to consumers depending on the hint format. * diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java index 2e86b80080..05aeda069b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java @@ -715,6 +715,7 @@ UpdateOptions getUpdateOptions(@Nullable Class domainType, @Nullable Consumer .arrayFilters(update.getArrayFilters().stream().map(ArrayFilter::asDocument).collect(Collectors.toList())); } + HintFunction.from(getQuery().getHint()).ifPresent(codecRegistryProvider, options::hintString, options::hint); applyCollation(domainType, options::collation); if (callback != null) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java index 3f4a63232e..2497812a3f 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java @@ -978,6 +978,28 @@ void updateManyShouldUseCollationWhenPresent() { assertThat(options.getValue().getCollation().getLocale()).isEqualTo("fr"); } + @Test // GH-3218 + void updateUsesHintStringFromQuery() { + + template.updateFirst(new Query().withHint("index-1"), new Update().set("spring", "data"), Human.class); + + ArgumentCaptor options = ArgumentCaptor.forClass(UpdateOptions.class); + verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture()); + + assertThat(options.getValue().getHintString()).isEqualTo("index-1"); + } + + @Test // GH-3218 + void updateUsesHintDocumentFromQuery() { + + template.updateFirst(new Query().withHint("{ name : 1 }"), new Update().set("spring", "data"), Human.class); + + ArgumentCaptor options = ArgumentCaptor.forClass(UpdateOptions.class); + verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture()); + + assertThat(options.getValue().getHint()).isEqualTo(new Document("name", 1)); + } + @Test // DATAMONGO-1518 void replaceOneShouldUseCollationWhenPresent() { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java index ec4e9e90f7..48b48a2e23 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java @@ -350,7 +350,28 @@ void updateManyShouldUseCollationWhenPresent() { verify(collection).updateMany(any(), any(Bson.class), options.capture()); assertThat(options.getValue().getCollation().getLocale()).isEqualTo("fr"); + } + + @Test // GH-3218 + void updateUsesHintStringFromQuery() { + + template.updateFirst(new Query().withHint("index-1"), new Update().set("spring", "data"), Person.class).subscribe(); + + ArgumentCaptor options = ArgumentCaptor.forClass(UpdateOptions.class); + verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture()); + + assertThat(options.getValue().getHintString()).isEqualTo("index-1"); + } + + @Test // GH-3218 + void updateUsesHintDocumentFromQuery() { + + template.updateFirst(new Query().withHint("{ firstname : 1 }"), new Update().set("spring", "data"), Person.class).subscribe(); + + ArgumentCaptor options = ArgumentCaptor.forClass(UpdateOptions.class); + verify(collection).updateOne(any(Bson.class), any(Bson.class), options.capture()); + assertThat(options.getValue().getHint()).isEqualTo(new Document("firstname", 1)); } @Test // DATAMONGO-1518 diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc index ebfc97e75b..45f54b6cab 100644 --- a/src/main/asciidoc/reference/mongodb.adoc +++ b/src/main/asciidoc/reference/mongodb.adoc @@ -922,6 +922,7 @@ Most methods return the `Update` object to provide a fluent style for the API. * *updateMulti*: Updates all objects that match the query document criteria with the updated document. WARNING: `updateFirst` does not support ordering. Please use <> to apply `Sort`. +NOTE: Index hints for the update operation can be provided via `Query.withHint(...)`. [[mongodb-template-update.update]] ==== Methods in the `Update` Class