I have a collection called Products
in my MongoDB database, which is represented by the interface IProductPrice
in my Java code. The following repo
using answer from Oliver Gierke above, working on a project where I need to create multiple collections for one entity, I wanted to use the spring repositories and needed to specify the entity to use before using the repository.
I managed to modify the repository collection name on demand using this system, it using SPeL. You can only work on 1 collection at a time though.
Domain object
@Document(collection = "#{personRepository.getCollectionName()}")
public class Person{}
Default Spring Repository:
public interface PersonRepository
extends MongoRepository<Person, String>, PersonRepositoryCustom{
}
Custom Repository Interface:
public interface PersonRepositoryCustom {
String getCollectionName();
void setCollectionName(String collectionName);
}
implementation:
public class PersonRepositoryImpl implements PersonRepositoryCustom {
private static String collectionName = "Person";
@Override
public String getCollectionName() {
return collectionName;
}
@Override
public void setCollectionName(String collectionName) {
this.collectionName = collectionName;
}
}
To use it:
@Autowired
PersonRepository personRepository;
public void testRetrievePeopleFrom2SeparateCollectionsWithSpringRepo(){
List<Person> people = new ArrayList<>();
personRepository.setCollectionName("collectionA");
people.addAll(personRepository.findAll());
personDocumentRepository.setCollectionName("collectionB");
people.addAll(personRepository.findAll());
Assert.assertEquals(4, people.size());
}
Otherwise if you need to use configuration variables, you could maybe use something like this? source
@Value("#{systemProperties['pop3.port'] ?: 25}")
I use static class and method in SpEL;
public class CollectionNameHolder {
private static final ThreadLocal<String> collectionNameThreadLocal = new ThreadLocal<>();
public static String get(){
String collectionName = collectionNameThreadLocal.get();
if(collectionName == null){
collectionName = DataCenterApiConstant.APP_WECHAT_DOCTOR_PATIENT_COLLECTION_NAME;
collectionNameThreadLocal.set(collectionName);
}
return collectionName;
}
public static void set(String collectionName){
collectionNameThreadLocal.set(collectionName);
}
public static void reset(){
collectionNameThreadLocal.remove();
}
}
In Entity class ,@Document(collection = "#{T(com.test.data.CollectionNameHolder).get()}")
And then ,use
CollectionNameHolder.set("testx_"+pageNum)
in Service , and
CollectionNameHolder.reset();
Hope it helps you.
The only way you can currently achieve this is by annotating your domain class with @Document
using the collection
property to define the name of the collection instances of this class shall be persisted to.
However, there's a JIRA issue open that suggests adding a pluggable naming strategy to configure the ways class, collection and property names are handled in a more global way. Feel free to comment your use case and vote it up.
A little late, but I've found you can set the mongo collection name dynamically in spring-boot accessing the application configuration directly.
@Document(collection = "#{@environment.getProperty('configuration.property.key')}")
public class DomainModel {...}
I suspect you can set any annotation attribute this way.
The only comment I can add is that you have to add @ prefix to the bean name:
collection = "#{@beanName.method()}"
for the bean factory to inject the bean:
@Document(collection = "#{@configRepositoryCustom.getCollectionName()}")
public class Config {
}
I struggled to figure it out..
COMPLETE EXAMPLE:
@Document(collection = "#{@configRepositoryCustom.getCollectionName()}")
public class Config implements Serializable {
@Id
private String uuid;
private String profile;
private String domain;
private String label;
private Map<String, Object> data;
// get/set
}
public interface ConfigRepositoryCustom {
String getCollectionName();
void setCollectionName(String collectionName);
}
@Component("configRepositoryCustom")
public class ConfigRepositoryCustomImpl implements ConfigRepositoryCustom {
private static String collectionName = "config";
@Override
public String getCollectionName() {
return collectionName;
}
@Override
public void setCollectionName(String collectionName) {
this.collectionName = collectionName;
}
}
@Repository("configurations")
public interface ConfigurationRepository extends MongoRepository<Config, String>, ConfigRepositoryCustom {
public Optional<Config> findOneByUuid(String Uuid);
public Optional<Config> findOneByProfileAndDomain(String profile, String domain);
}
usage in serviceImpl:
@Service
public class ConfigrationServiceImpl implements ConfigrationService {
@Autowired
private ConfigRepositoryCustom configRepositoryCustom;
@Override
public Config create(Config configuration) {
configRepositoryCustom.setCollectionName( configuration.getDomain() ); // set the collection name that comes in my example in class member 'domain'
Config configDB = configurationRepository.save(configuration);
return configDB;
}