Is it possible to load initial data in a MongoDB database using src/main/resources/data.sql or by any other file?
I understand that data.sql is used for SQL DB's whereas MongoDB is a NOSQL DB. But just wanted to know if there is any equivalent of data.sql for NOSQL DB's.
While googling I found out this SO link (Spring Boot - Loading Initial Data) which does what I am looking for but still it's not a standalone file data.sql.
To load initial data you can use db migration tool like MongoBee
It's very useful option to handle data initialization in java. You just need to configure #Bean public Mongobee mongobee in your spring boot and setup component scan for data ChangeLogs where data creation actually happens.
You can use a repository populator with Spring Data MongoDB. Let me demonstrate this with a code sample in Kotlin:
#Configuration
class TestApplicationConfig {
#Value("classpath:test_data.json")
private lateinit var testData: Resource
#Bean
#Autowired
fun repositoryPopulator(objectMapper: ObjectMapper): Jackson2RepositoryPopulatorFactoryBean {
val factory = Jackson2RepositoryPopulatorFactoryBean()
// inject your Jackson Object Mapper if you need to customize it:
factory.setMapper(objectMapper)
factory.setResources(arrayOf(testData))
return factory
}
}
Put test_data.json in resources directory.
you can define your data in json/xml and use populator elements of the repository to load the data.
https://docs.spring.io/spring-data/mongodb/docs/2.0.9.RELEASE/reference/html/#core.repository-populators
Related
My Spring boot application has a multitenancy architecture and I'm using Javers to audit some data models.
The issue I'm facing is that Javers is not able to resolve the database based on my MongoDatabaseFactory implementation.
So far I've tried creating a Javers Configuration Bean which looks like this:
#Component
public class JaversMongoConfiguration {
#Autowired
CachedMongoClients cachedMongoClients;
#SneakyThrows
public Javers javers() {
MongoRepository javersMongoRepository =
new MongoRepository(cachedMongoClients.getMongoDatabaseForCurrentContext()); // Custom method to fetch the MongoDataBase based on current TenantContext
return JaversBuilder.javers()
.registerJaversRepository(javersMongoRepository)
.build();
}
}
This isn't working as during project build time, Javers instantiates the connection to the default database and dynamically doesn't switch to the tenant database as intended during run time.
Hence, all my audit logs are getting saved at the default database and not in tenant database.
Note: I'm using Javers Spring Boot Mongo starter and Javers Mongo Persistence Maven dependencies.
In Javers there is no integration with Spring multitenancy. Javers is open source, you are encouraged to contribute https://github.com/javers/javers/
I have a need to dynamically create and connect to potentially hundreds of databases using from a single ResourceServer (REST Server). The REST controller would do something like this:
#RequestMapping("/teachers")
public List<Teacher> teachers(#RequestParam(value="db", defaultValue="db") String db) {
//Look up the correct datasource
DataSource ds = DSSources.get(db);
//Associate the datasource with the repository
...
//Return the teachers from the database using
//the TeacherRepository (Spring Data JPA Repository)
return TeacherRepository.getAllTeachers();
}
I'm thinking that the DSSources is a Map<String, Datasource that contains the DataSource instances. How do I programmatically create the datasources? Once they are created, how are they associated with the Spring Data JPA Repositories? All databases will share a common set of repositories.
Storing Datasource in a Map is not a good solution has you have to think of Datasources failing and recreating those as well.
What you need is Multi Tenancy. If you use Hibernate underneath JPA you can use Hibernate Multi Tenancy. I am pretty sure other ORMs also do provide Multi Tenancy capabilities.
I come from php/laravel. Whenever I want to seed the database i only need to run php artisan db:seed. This will run some php scripts that will insert data into the database.
I want to achieve this same feature using spring/hibernate. I know I can add an import.sql file to seed the database after schema creation. However, I want to import these fixtures using java and the ORM available so I do not need to maintain an sql.
Is there a way?
If not, there should be some configuration to trigger a script that use the ORM entity manager to persist entities in the database after schema creation.
The main idea is not to maintain a big sql seeder file over schema revisions.
Thanks!
If you're using Spring data you can use Repository populators.
Otherwise you may register an event that fires after the spring context is loaded :
#Component
public class YourListener {
// Declare your autowired beans here
#EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
// Your seeder
// + You can use all the registred beans (repositories, services...)
}
}
For more detail check: Better application events in Spring Framework 4.2
How can I set the name of an embedded database started in a Spring Boot app running in a test?
I'm starting two instances of the same Spring Boot app as part of a test, as they collaborate. They are both correctly starting an HSQL database, but defaulting to a database name of testdb despite being provided different values for spring.datasource.name.
How can I provide different database names, or some other means of isolating the two databases? What is going to be the 'lightest touch'? If I can avoid it, I'd rather control this with properties than adding beans to my test config - the test config classes shouldn't be cluttered up because of this one coarse-grained collaboration test.
Gah - setting spring.datasource.name changes the name of the datasource, but not the name of the database.
Setting spring.datasource.url=jdbc:hsql:mem:mydbname does exactly what I need it to. It's a bit crap that I have to hardcode the embedded database implementation, but Spring Boot is using an enum for default values, which would mean a bigger rewrite if it were to try getting the name from a property.
You can try it so:
spring.datasource1.name=testdb
spring.datasource2.name=otherdb
And then declare datasource in your ApplicationConfig like this
#Bean
#ConfigurationProperties(prefix="spring.datasource1")
public DataSource dataSource1() {
...
}
#Bean
#ConfigurationProperties(prefix="spring.datasource2")
public DataSource dataSource2() {
...
}
See official docs for more details: https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html#howto-configure-a-datasource
I do not want to utilize the Spring DATA MongoDB support.
I want to leverage the ORM for MongoDB called Morphia.
https://github.com/mongodb/morphia
I want to configure the Morphia with Spring Boot. I want to externalize the configuration of Morphia in a way that it follows the Spring Boot philosophy.
I want to leverage the environment variables for the configuration of Morphia properties.
What would be the Spring Boot approach to achieve this ?
In a simple main program on would do following to get the Morhpia ORM working.
private Morphia morphia;
private MongoClient mongoClient;
morphia = new Morphia();
// Person is an entity object with Morphia annotations
morphia.map(Person.class);
// THESE properties MUST be read from environment variables in Spring BOOT.
final String host = "localhost";
final int port = 27017;
mongoClient = new MongoClient(host, port);
//Set database
// this instance would be autowired all data access classes
Datastore ds = morphia.createDatastore(mongoClient, "dataStoreInstanceId");
// this is how instance would be used in those data accesses classes
Person p = ds.find(Person.class, "username", "john").get();
The Spring Boot like approach would be to create a AutoConfiguration with the needed properties which creates an instance of Datastore as bean.
In the Reference Guide you will find how to set properties and connect to a MongoDB.
An AutoConfiguration for Morphia could look like this:
#Configuration
public class MorphiaAutoConfiguration {
#Autowired
private MongoClient mongoClient; // created from MongoAutoConfiguration
#Bean
public Datastore datastore() {
Morphia morphia = new Morphia();
// map entities, there is maybe a better way to find and map all entities
ClassPathScanningCandidateComponentProvider entityScanner = new ClassPathScanningCandidateComponentProvider(true);
entityScanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
for (BeanDefinition candidate : scanner.findCandidateComponents("your.basepackage")) { // from properties?
morphia.map(Class.forName(candidate.getBeanClassName()));
}
return morphia.createDatastore(mongoClient, "dataStoreInstanceId"); // "dataStoreInstanceId" may come from properties?
}
}
You could then autowire your Datastore in other Spring beans the usual way:
#Autowired
private Datastore datastore;
If some points are not correct or unclear just take a look at the existing *AutoConfiguration classes in Spring Boot.
I'm working in a starter for spring boot, here is the repo. Is very easy to use, in some days will update it in maven central.