diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java
index 18f8b269be..a3928e40ae 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/Query.java
@@ -33,6 +33,7 @@
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
+ * @author Jorge Rodríguez
*/
@Collation
@Retention(RetentionPolicy.RUNTIME)
@@ -40,6 +41,7 @@
@Documented
@QueryAnnotation
@Hint
+@ReadPreference
public @interface Query {
/**
@@ -147,4 +149,21 @@
*/
@AliasFor(annotation = Hint.class, attribute = "indexName")
String hint() default "";
+
+ /**
+ * The mode of the read preference to use.
+ * {@code @Query(value = "...", readPreference = "secondary")} can be used as shortcut for:
+ *
+ *
+ * @Query(...)
+ * @ReadPreference("secondary")
+ * List<User> findAllByLastname(String collation);
+ *
+ *
+ * @return the index name.
+ * @since 4.2
+ * @see ReadPreference#value()
+ */
+ @AliasFor(annotation = ReadPreference.class, attribute = "value")
+ String readPreference() default "";
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreference.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreference.java
new file mode 100644
index 0000000000..2ba4e32fd7
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreference.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mongodb.repository;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to declare read preference for repository and query.
+ *
+ * @author Jorge Rodríguez
+ * @since 4.2
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
+@Documented
+public @interface ReadPreference {
+
+ /**
+ * Configure read preference mode
+ * @return read preference mode
+ */
+ String value() default "";
+
+ /**
+ * Set read preference tags
+ * @return read preference tags
+ */
+ ReadPreferenceTag[] tags() default {};
+
+ /**
+ * Set read preference maxStalenessSeconds
+ * @return read preference maxStalenessSeconds
+ */
+ long maxStalenessSeconds() default -1;
+}
+
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreferenceTag.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreferenceTag.java
new file mode 100644
index 0000000000..5fae877ee2
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/ReadPreferenceTag.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mongodb.repository;
+
+/**
+ * Annotation used by {@link ReadPreference} for define {@link com.mongodb.Tag}
+ *
+ * @author Jorge Rodríguez
+ * @since 4.2
+ */
+public @interface ReadPreferenceTag {
+
+ /**
+ * Set the name of tag
+ * @return name of tag
+ */
+ String name();
+
+ /**
+ * Set the value of tag
+ * @return value of tag
+ */
+ String value();
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java
index e8d69504d7..0913a9fb4b 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java
@@ -62,6 +62,7 @@
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
+ * @author Jorge Rodríguez
*/
public abstract class AbstractMongoQuery implements RepositoryQuery {
@@ -137,6 +138,7 @@ protected Object doExecute(MongoQueryMethod method, ResultProcessor processor, C
query = applyAnnotatedDefaultSortIfPresent(query);
query = applyAnnotatedCollationIfPresent(query, accessor);
query = applyHintIfPresent(query);
+ query = applyAnnotatedReadPreferenceIfPresent(query);
FindWithQuery> find = typeToRead == null //
? executableFind //
@@ -145,6 +147,22 @@ protected Object doExecute(MongoQueryMethod method, ResultProcessor processor, C
return getExecution(accessor, find).execute(query);
}
+ /**
+ * If present apply the {@link com.mongodb.ReadPreference} from the {@link org.springframework.data.mongodb.repository.ReadPreference} annotation.
+ *
+ * @param query must not be {@literal null}.
+ * @return never {@literal null}.
+ * @since 4.2
+ */
+ private Query applyAnnotatedReadPreferenceIfPresent(Query query) {
+
+ if (!method.hasAnnotatedReadPreference()) {
+ return query;
+ }
+
+ return query.withReadPreference(method.getAnnotatedReadPreference());
+ }
+
private MongoQueryExecution getExecution(ConvertingParameterAccessor accessor, FindWithQuery> operation) {
if (isDeleteQuery()) {
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java
index fb430a1517..51301697e5 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java
@@ -66,6 +66,7 @@
*
* @author Mark Paluch
* @author Christoph Strobl
+ * @author Jorge Rodríguez
* @since 2.0
*/
public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
@@ -161,6 +162,8 @@ protected Publisher