spring-projects / spring-data-mongodb

Provides support to increase developer productivity in Java when using MongoDB. Uses familiar Spring concepts such as a template classes for core API usage and lightweight repository style data access.
https://spring.io/projects/spring-data-mongodb/
Apache License 2.0
1.61k stars 1.08k forks source link

`MongoTemplate.indexOps(collectionName, type)` ignores collectionName when type is not `null` #4698

Closed Typraeurion closed 4 months ago

Typraeurion commented 4 months ago

I have an object type that is stored in MongoDB under two tables: one using the default (class) table name, another using a custom name. The code needs to ensure a geospatial index exists on the table before doing a “near” query. It looks something like this:

        getMongoTemplate().indexOps("topPlaces", Place.class).ensureIndex(
                new GeospatialIndex("location")
                        .typed(GeoSpatialIndexType.GEO_2DSPHERE));

        GeoResults<Place> results = getMongoTemplate()
                .geoNear(nearQuery, Place.class, "topPlaces");

When executing the query, it fails with:

$geoNear requires a 2d or 2dsphere index, but none were found' on server localhost:27017

and checking the tables in mongosh I found the index was created on the “place” table, not on “topPlaces”. I traced the fault down to this line in DefaultIndexOperations.execute(callback):

https://github.com/spring-projects/spring-data-mongodb/blob/7821c2a545da5ac10529f0158639e998dfb0072a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/DefaultIndexOperations.java#L212

which prioritizes executing the callback for the type of the collection if present over the collectionName.

If this is the intended behavior of indexOps(collectionName, type), it’s not documented. The javadoc implies that the type parameter is only used for field mapping. It also says that collectionName is required, even though it isn’t used.

(Caveat: I’m currently running with spring-data-mongodb 4.0.12, but it appears this execute method has not been changed in the latest code here on GitHub.)

mp911de commented 4 months ago

execute(Class<?> entityClass, CollectionCallback<T> callback) merely derives the collection name from a given type. While this can be useful for cases where the collection name is dynamic (e.g. by using SpEL expressions), we should rather capture the collection name that was given during index operations creations. The reactive counterpart of index operations sticks already to the given collection name.

That being said, I consider this behavior a bug.