Skip to content

@CompoundIndex ignores partialFilter when creating index & crashes on 2nd boot #4746

@keydon

Description

@keydon

Spring Data MongoDb 4.2.5
Monng Driver 4.11.2

When I try to create a partial index like this

@CompoundIndex(name = "regular_messages",
          def = "{'channelId' : -1, 'timestamp': -1}",
          partialFilter = """
            {
                'scheduled': { '$eq': false },
                'type': { '$in': ['edit', 'editScheduled', 'original'] }, $comment: 'exclude deleted'
            }
          """
        )

no errors are thrown, but the index created lacks the partial filter.
In addition, when booting the spring boot app a second time, it tries to recreate the index and fails with:

aused by: org.springframework.dao.DataIntegrityViolationException: Cannot create index for '' in collection 'message' with keys 'Document{{channelId=-1, timestamp=-1}}' and options 'Document{{name=regular_messages, partialFilterExpression=Document{{scheduled=Document{{$eq=false}}, type=Document{{$in=[edit, editScheduled, original]}}, $comment=exclude deleted}}}}' Index already defined as 'IndexInfo [indexFields=[IndexField [ key: channelId, direction: DESC, type: DEFAULT, weight: NaN], IndexField [ key: timestamp, direction: DESC, type: DEFAULT, weight: NaN]], name=regular_messages, unique=false, sparse=false, language=, partialFilterExpression=null, collation=null, expireAfterSeconds=null, hidden=false]'
	at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.createIndex(MongoPersistentEntityIndexCreator.java:170)
	at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.checkForAndCreateIndexes(MongoPersistentEntityIndexCreator.java:143)
	at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.checkForIndexes(MongoPersistentEntityIndexCreator.java:127)
	at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.<init>(MongoPersistentEntityIndexCreator.java:96)
	at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.<init>(MongoPersistentEntityIndexCreator.java:73)
	at org.springframework.data.mongodb.core.MongoTemplate.<init>(MongoTemplate.java:263)
	at org.springframework.boot.autoconfigure.data.mongo.MongoDatabaseFactoryDependentConfiguration.mongoTemplate(MongoDatabaseFactoryDependentConfiguration.java:61)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140)
	... 44 common frames omitted
Caused by: com.mongodb.MongoCommandException: Command failed with error 86 (IndexKeySpecsConflict): 'An existing index has the same name as the requested index. When index names are not specified, they are auto generated and can cause conflicts. Please refer to our documentation. Requested index: { v: 2, key: { channelId: -1, timestamp: -1 }, name: "regular_messages", partialFilterExpression: { scheduled: { $eq: false }, type: { $in: [ "edit", "editScheduled", "original" ] }, $comment: "exclude deleted" } }, existing index: { v: 2, key: { channelId: -1, timestamp: -1 }, name: "regular_messages" }' on server localhost:32970. The full response is {"ok": 0.0, "errmsg": "An existing index has the same name as the requested index. When index names are not specified, they are auto generated and can cause conflicts. Please refer to our documentation. Requested index: { v: 2, key: { channelId: -1, timestamp: -1 }, name: \"regular_messages\", partialFilterExpression: { scheduled: { $eq: false }, type: { $in: [ \"edit\", \"editScheduled\", \"original\" ] }, $comment: \"exclude deleted\" } }, existing index: { v: 2, key: { channelId: -1, timestamp: -1 }, name: \"regular_messages\" }", "code": 86, "codeName": "IndexKeySpecsConflict", "$clusterTime": {"clusterTime": {"$timestamp": {"t": 1721208649, "i": 1}}, "signature": {"hash": {"$binary": {"base64": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "subType": "00"}}, "keyId": 0}}, "operationTime": {"$timestamp": {"t": 1721208649, "i": 1}}}
	at com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:205)
	at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:454)
	at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:372)
	at com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:114)
	at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:765)
	at com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:76)
	at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:209)
	at com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:115)
	at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:83)
	at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:74)
	at com.mongodb.internal.connection.DefaultServer$OperationCountTrackingConnection.command(DefaultServer.java:299)
	at com.mongodb.internal.operation.SyncOperationHelper.executeCommand(SyncOperationHelper.java:210)
	at com.mongodb.internal.operation.CreateIndexesOperation.lambda$execute$0(CreateIndexesOperation.java:131)
	at com.mongodb.internal.operation.SyncOperationHelper.withConnectionSource(SyncOperationHelper.java:163)
	at com.mongodb.internal.operation.SyncOperationHelper.withConnection(SyncOperationHelper.java:108)
	at com.mongodb.internal.operation.CreateIndexesOperation.execute(CreateIndexesOperation.java:129)
	at com.mongodb.internal.operation.CreateIndexesOperation.execute(CreateIndexesOperation.java:68)
	at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:173)
	at com.mongodb.client.internal.MongoCollectionImpl.executeCreateIndexes(MongoCollectionImpl.java:913)
	at com.mongodb.client.internal.MongoCollectionImpl.createIndexes(MongoCollectionImpl.java:896)
	at com.mongodb.client.internal.MongoCollectionImpl.createIndexes(MongoCollectionImpl.java:891)
	at com.mongodb.client.internal.MongoCollectionImpl.createIndex(MongoCollectionImpl.java:876)
	at org.springframework.data.mongodb.core.DefaultIndexOperations.lambda$ensureIndex$0(DefaultIndexOperations.java:129)
	at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:601)
	at org.springframework.data.mongodb.core.DefaultIndexOperations.execute(DefaultIndexOperations.java:215)
	at org.springframework.data.mongodb.core.DefaultIndexOperations.ensureIndex(DefaultIndexOperations.java:119)
	at org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.createIndex(MongoPersistentEntityIndexCreator.java:153)
	... 53 common frames omitted

when I create the index manually with mongock it works fine

    @Execution
    public void createIndex(){
        var idx = new Index()
            .named("regular_messages")
            .on("channelId", Sort.Direction.DESC)
            .on("timestamp", Sort.Direction.DESC)
            .partial(PartialIndexFilter.of(
                    where("scheduled").is(false)
                    .and("type").in(List.of("edit", "original"))
            ));
        mongoOperations.indexOps(Message.class)
                .ensureIndex(idx);
    }

Results of each approach in MongoDB Compass:
image

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions