admin管理员组

文章数量:1291818

I am using Spring Boot with MongoDB and implementing a multi-tenant architecture where each tenant has a separate database. I set the database dynamically using a custom MongoDatabaseFactory.

Even though I have @Indexed annotations in my entity classes and spring.data.mongodb.auto-index-creation=true in application.properties, indexes are not being created automatically when a new tenant database is initialized.

Note: I have no problems with dynamically changing database, CRUD operations, everything works properly, only index creation does not work.

What I tried:

  • Enabled debug logging → No logs showing index creation attempts.
  • Checked MongoDB shell (db.getIndexes()) → Only the default _id index is there.
  • Manually creating indexes works (db.collection.createIndex(...)).

My Question:

How can I make Spring Boot automatically create indexes for new tenant databases when they are first accessed?

My dynamic database changing codes:

class MultiTenantMongoDbFactory(
    private val mongoClient: MongoClient
) : MongoDatabaseFactory {

    private val exceptionTranslator = MongoExceptionTranslator()

    override fun getSession(options: ClientSessionOptions): ClientSession {
        return mongoClient.startSession(options)
    }

    override fun getMongoDatabase(): MongoDatabase {
        val dbName = DatabaseContext.getDatabaseName()
        println("Switching to database: $dbName")
        return mongoClient.getDatabase(dbName)
    }

    override fun getMongoDatabase(dbName: String): MongoDatabase {
        return mongoClient.getDatabase(dbName)
    }

    override fun getExceptionTranslator(): PersistenceExceptionTranslator {
        return exceptionTranslator
    }

    override fun withSession(session: ClientSession): MongoDatabaseFactory {
        return MultiTenantMongoDbFactory(mongoClient).apply {
            session
        }
    }
}
@Configuration
class MongoConfiguration {

    @Value("\${SPRING_DATA_MONGODB_URI}")
    lateinit var mongoURI: String

    @Bean
    fun mongoClient(): MongoClient {
        return MongoClients.create(mongoURI)
    }

    @Bean
    @Primary
    fun multiTenantMongoDatabaseFactory(mongoClient: MongoClient): MultiTenantMongoDbFactory {
        return MultiTenantMongoDbFactory(mongoClient)
    }

    @Bean
    fun mongoTemplate(multiTenantMongoDatabaseFactory: MultiTenantMongoDbFactory): MongoTemplate {
        val mongoTemplate = MongoTemplate(multiTenantMongoDatabaseFactory)
        mongoTemplate.setReadPreference(ReadPreference.secondaryPreferred())
        return mongoTemplate
    }
}
object DatabaseContext {
    private val contextHolder = ThreadLocal<String>()
    private const val DEFAULT_DATABASE = "mydb"

    fun setDatabaseName(dbName: String) {
        contextHolder.set(dbName)
    }

    fun getDefaultDatabaseName(): String {
        return DEFAULT_DATABASE
    }

    fun getDatabaseName(): String {
        return contextHolder.get() ?: DEFAULT_DATABASE
    }

    fun clear() = contextHolder.remove()
}

Example data class;

@Document(collection = "users")
data class User(
    @Id
    val userId: String? = null,

    @Indexed(name = "user_uuid_1", unique = true)
    @Field("user_uuid")
    var userUuid: String
)

application.properties;

spring.data.mongodb.auto-index-creation=true
logging.level.springframework.data.mongodb=DEBUG
logging.level.springframework.data.mongodb.core.index=DEBUG
...
...

I am using Spring Boot with MongoDB and implementing a multi-tenant architecture where each tenant has a separate database. I set the database dynamically using a custom MongoDatabaseFactory.

Even though I have @Indexed annotations in my entity classes and spring.data.mongodb.auto-index-creation=true in application.properties, indexes are not being created automatically when a new tenant database is initialized.

Note: I have no problems with dynamically changing database, CRUD operations, everything works properly, only index creation does not work.

What I tried:

  • Enabled debug logging → No logs showing index creation attempts.
  • Checked MongoDB shell (db.getIndexes()) → Only the default _id index is there.
  • Manually creating indexes works (db.collection.createIndex(...)).

My Question:

How can I make Spring Boot automatically create indexes for new tenant databases when they are first accessed?

My dynamic database changing codes:

class MultiTenantMongoDbFactory(
    private val mongoClient: MongoClient
) : MongoDatabaseFactory {

    private val exceptionTranslator = MongoExceptionTranslator()

    override fun getSession(options: ClientSessionOptions): ClientSession {
        return mongoClient.startSession(options)
    }

    override fun getMongoDatabase(): MongoDatabase {
        val dbName = DatabaseContext.getDatabaseName()
        println("Switching to database: $dbName")
        return mongoClient.getDatabase(dbName)
    }

    override fun getMongoDatabase(dbName: String): MongoDatabase {
        return mongoClient.getDatabase(dbName)
    }

    override fun getExceptionTranslator(): PersistenceExceptionTranslator {
        return exceptionTranslator
    }

    override fun withSession(session: ClientSession): MongoDatabaseFactory {
        return MultiTenantMongoDbFactory(mongoClient).apply {
            session
        }
    }
}
@Configuration
class MongoConfiguration {

    @Value("\${SPRING_DATA_MONGODB_URI}")
    lateinit var mongoURI: String

    @Bean
    fun mongoClient(): MongoClient {
        return MongoClients.create(mongoURI)
    }

    @Bean
    @Primary
    fun multiTenantMongoDatabaseFactory(mongoClient: MongoClient): MultiTenantMongoDbFactory {
        return MultiTenantMongoDbFactory(mongoClient)
    }

    @Bean
    fun mongoTemplate(multiTenantMongoDatabaseFactory: MultiTenantMongoDbFactory): MongoTemplate {
        val mongoTemplate = MongoTemplate(multiTenantMongoDatabaseFactory)
        mongoTemplate.setReadPreference(ReadPreference.secondaryPreferred())
        return mongoTemplate
    }
}
object DatabaseContext {
    private val contextHolder = ThreadLocal<String>()
    private const val DEFAULT_DATABASE = "mydb"

    fun setDatabaseName(dbName: String) {
        contextHolder.set(dbName)
    }

    fun getDefaultDatabaseName(): String {
        return DEFAULT_DATABASE
    }

    fun getDatabaseName(): String {
        return contextHolder.get() ?: DEFAULT_DATABASE
    }

    fun clear() = contextHolder.remove()
}

Example data class;

@Document(collection = "users")
data class User(
    @Id
    val userId: String? = null,

    @Indexed(name = "user_uuid_1", unique = true)
    @Field("user_uuid")
    var userUuid: String
)

application.properties;

spring.data.mongodb.auto-index-creation=true
logging.level..springframework.data.mongodb=DEBUG
logging.level..springframework.data.mongodb.core.index=DEBUG
...
...
Share Improve this question asked Feb 13 at 13:06 Ozgur BaykalOzgur Baykal 4232 silver badges13 bronze badges 2
  • It must be a lifecycle matter. I reckon your Spring Boot App starts up, connects to the "default" database then does its Index checking. Later you switch database, but now it is too late. So dig around to look for how/when the index creation process executes and work from there; perhaps you can re-invoke the index check/creation code. – AndrewL Commented Feb 17 at 23:10
  • Yes you are right, when Spring Boot first starts, it connects to a default database and creates indexes only for that database. However, when I dynamically change the database, it cannot apply these indexes to other databases. And there is no solution. So I have to create indexes for each database manually from MongoDB Compass or shell. (Or as I do now, when a customer is created in CRM, I switch to the customer's database and create indexes manually with indexOps()). – Ozgur Baykal Commented Feb 21 at 12:27
Add a comment  | 

1 Answer 1

Reset to default 1

When Spring Boot first starts, it connects to a default database and creates indexes only for that database.

However, when I dynamically change the database, it cannot apply these indexes to other databases. And there is no solution for this.

So you have to manually create indexes for each database from MongoDB Compass or shell.

Or as I am doing now, when a customer is created in CRM, I switch to the customer's database and create indexes manually with indexOps().

You can solve the problem if you include this code it in a scenario where you create a new database.

DatabaseContext.setDatabaseName(request.dbName)

mongoTemplate.indexOps("devices").ensureIndex(
    Index().on("device_uuid", Sort.Direction.ASC).unique()
)

mongoTemplate.indexOps("devices").ensureIndex(
    Index().on("user_uuid", Sort.Direction.ASC)
)

mongoTemplate.indexOps("devices").ensureIndex(
    Index().on("is_active", Sort.Direction.ASC)
)

mongoTemplate.indexOps("users").ensureIndex(
    Index().on("user_uuid", Sort.Direction.ASC).unique()
)

本文标签: MongoDB Indexes Not Created Automatically in Spring Boot with MultiTenant DatabaseStack Overflow