Reputation: 55
I am connecting to a MongoDB sharding server via mongodb java driver in Spring MVC. I am using the following versions:
My Mongo options are set in the contextConfigLocation file mvc-dispatcher-servlet.xml
<mongo:mongo host="mongo.sample.com" port="30000">
<mongo:options auto-connect-retry="true"
slave-ok="true"/>
</mongo:mongo>
It works pretty well, but the slave-ok is deprecated by come.MongoDB.ReadPreference. I just wonder if there is any way to set the readPreference for Spring MVC in the contextConfiLocation file.
Upvotes: 5
Views: 18228
Reputation: 11
If you have to use Spring's "MongoOperations", like I have to because we have a collection with a dot (.) in its name, and I am not allowed to rename the collection. You can still set the read preference on the "Aggregation" Object via "AggregationOptions". Here is an example:
AggregationOptions aggOps = AggregationOptions.builder().readPreference(
com.mongodb.ReadPreference.secondaryPreferred()).build();
Aggregation agg = Aggregation.newAggregation(match, buildRuntimeProjection()).withOptions(aggOps);
And by the way you can use both MongoRepository and MongoOperations in the same class. I am using both in a test app I am writing.
Upvotes: 0
Reputation: 11
If you are using SpringBoot's "MongoRepository" interface you can just add the @ReadPreference("secondaryPreferred") to the method.
public interface MyRepository extends MongoRepository<MyItem, String>
{
@ReadPreference("secondaryPreferred")
public Optional<MyItem> findById(String id);
Upvotes: 0
Reputation: 497
Or you can define at the query level with annotation in the repository interface:
@Meta(flags = CursorOption.SECONDARY_READS)
Stream<MyClass> findBySomeField(String someField);
Which is really useful when using spring generated queries from method names or annotations like @Query or @Aggregation
Upvotes: 0
Reputation: 161
Here is one more way to do this using Mongo Repositories
@Configuration
@EnableMongoRepositories
class ApplicationConfig extends AbstractMongoClientConfiguration {
@Autowired
private Environment env;
@Value("${spring.data.mongodb.uri}")
public String mongoUri;
@Override
protected String getDatabaseName() {
return env.getProperty("spring.data.mongodb.database");
}
@Override
protected void configureClientSettings(MongoClientSettings.Builder builder) {
builder.applyConnectionString(new ConnectionString(mongoUri)).readPreference(ReadPreference.secondary());
}
}
sample app available @ https://github.com/prashanthmadi/cosmosdb-mongodb-readpreference-springboot-java/blob/main/src/main/java/azure/cosmosdb/mongodb/spring/cosmosdbmongodb/ApplicationConfig.java
Upvotes: 2
Reputation: 421
As of spring-mongo-2.0.xsd, slave-ok
has been entirely removed, but support has been added for XML config of ReadPreference
. Here's the XML from the original question translated for the current XSD:
<mongo:mongo-client host="mongo.sample.com" port="30000">
<mongo:client-options read-preference="SECONDARY_PREFERRED" />
</mongo:mongo-client>
Upvotes: 0
Reputation: 726
If there is a need to mix between primary and secondary for reads depending on the collection, you can set the ReadPreference
on the DBCollection
object. This helps to avoid complex multiple MongoTemplate
configuration. Instead, set collection level preference like below once in the application lifetime. All the reads for that specific collection will go to secondary, while for other collections it goes to primary.
DBCollection dbCollection = mongoTemplate.getCollection(mongoTemplate.getCollectionName(collection));
dbCollection.setReadPreference(ReadPreference.secondaryPreferred());
If you want to know different options to achieve it, please check Spring data mongodb secondary reads
Upvotes: 0
Reputation: 41
In case you are using spring-data-mongodb and have some requirement to use multiple Read Preferences based on find query, you can create multiple Mongo Templates and/or Repositories like
@EnableMongoRepositories(basePackages = {
"com.you.repo.package" }, mongoTemplateRef = "mongoTemplateOne")
@Configuration
public class MongoConfig {
@Bean(name="mongoTemplateOne")
public MongoTemplate getMongoTemplateOne() throws UnknownHostException {
MongoTemplate templateOne = new MongoTemplate(new SimpleMongoDbFactory(new MongoClientURI("YOUR_MONGO_URL")));
templateOne.setReadPreference(ReadPreference.secondaryPreferred());
//setting WriteConcern but not relevant for this thread
templateOne.setWriteConcernResolver(yourWriteConcernResolver());
return templateOne;
}
@Bean(name = "mongoTemplateTwo")
public MongoTemplate getMongoTemplateTwo() throws UnknownHostException {
MongoTemplate templateTwo = new MongoTemplate(new SimpleMongoDbFactory(new MongoClientURI("YOUR_MONGO_URL")));
templateTwo.setReadPreference(ReadPreference.secondaryPreferred());
return templateTwo;
}
private WriteConcernResolver yourWriteConcernResolver() {
return action -> {
if (action.getCollectionName()
.equals("your_collecton")
&& (action.getMongoActionOperation() == MongoActionOperation.SAVE
|| action.getMongoActionOperation() == MongoActionOperation.UPDATE)) {
return WriteConcern.MAJORITY;
}
return action.getDefaultWriteConcern();
};
}
Upvotes: 4
Reputation: 1712
In case you have more than one secondary (replica-set) you can be more specific and tell the mongo driver explicitly which of the secondaries you want to read from, using tags.
On the mongo side you run this command:
db.getMongo().setReadPref('secondaryPreferred',
[{"tagName":"TagVal1"},
{"tagName":"TagVal2"},
{}])
In the code it looks like this:
MongoTemplate template = new MongoTemplate(...)
template.setReadPreference(ReadPreference.secondaryPreferred("your DBObject that reflect your mongo tag names");
Hope it helps.
Upvotes: 2
Reputation: 12007
Declare the following bean
<bean id="readPreferenceSecondary" class="com.mongodb.TaggableReadPreference.SecondaryReadPreference">
</bean>
and
you inject this in your mongotemplate
<bean id="mongoTemplateProdDb" class="org.springframework.data.mongodb.core.MongoTemplate" >
<property name="readPreference" ref="readPreferenceSecondary"></property>
</bean>
Upvotes: 9
Reputation: 3689
Expanding @Trisha's response in to an answer: "Do it in MongoTemplate programmatically" by setting the ReadPreference
to SECONDARY
.
MongoTemplate template = new MongoTemplate(...);
template.setReadPreference(com.mongodb.ReadPreference.SECONDARY);
Upvotes: 8