diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java
index 55fee13fa..eb31e7a96 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/CompoundIndex.java
@@ -73,7 +73,43 @@ public @interface CompoundIndex {
boolean dropDups() default false;
/**
- * The name of the index to be created.
+ * The name of the index to be created.
+ *
+ * The name will only be applied as is when defined on root level. For usage on nested or embedded structures the
+ * provided name will be prefixed with the path leading to the entity.
+ *
+ * The structure below
+ *
+ *
+ *
+ * @Document
+ * class Root {
+ * Hybrid hybrid;
+ * Nested nested;
+ * }
+ *
+ * @Document
+ * @CompoundIndex(name = "compound_index", def = "{'h1': 1, 'h2': 1}")
+ * class Hybrid {
+ * String h1, h2;
+ * }
+ *
+ * @CompoundIndex(name = "compound_index", def = "{'n1': 1, 'n2': 1}")
+ * class Nested {
+ * String n1, n2;
+ * }
+ *
+ *
+ *
+ * resolves in the following index structures
+ *
+ *
+ *
+ * db.root.ensureIndex( { hybrid.h1: 1, hybrid.h2: 1 } , { name: "hybrid.compound_index" } )
+ * db.root.ensureIndex( { nested.n1: 1, nested.n2: 1 } , { name: "nested.compound_index" } )
+ * db.hybrid.ensureIndex( { h1: 1, h2: 1 } , { name: "compound_index" } )
+ *
+ *
*
* @return
*/
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java
index 3bf128c14..7b4c09c79 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/GeoSpatialIndexed.java
@@ -32,7 +32,41 @@ import java.lang.annotation.Target;
public @interface GeoSpatialIndexed {
/**
- * Name of the property in the document that contains the [x, y] or radial coordinates to index.
+ * Index name.
+ *
+ * The name will only be applied as is when defined on root level. For usage on nested or embedded structures the
+ * provided name will be prefixed with the path leading to the entity.
+ *
+ * The structure below
+ *
+ *
+ *
+ * @Document
+ * class Root {
+ * Hybrid hybrid;
+ * Nested nested;
+ * }
+ *
+ * @Document
+ * class Hybrid {
+ * @GeoSpatialIndexed(name="index") Point h1;
+ * }
+ *
+ * class Nested {
+ * @GeoSpatialIndexed(name="index") Point n1;
+ * }
+ *
+ *
+ *
+ * resolves in the following index structures
+ *
+ *
+ *
+ * db.root.ensureIndex( { hybrid.h1: "2d" } , { name: "hybrid.index" } )
+ * db.root.ensureIndex( { nested.n1: "2d" } , { name: "nested.index" } )
+ * db.hybrid.ensureIndex( { h1: "2d" } , { name: "index" } )
+ *
+ *
*
* @return
*/
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java
index 73aaeb15e..a907d4770 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/Indexed.java
@@ -58,7 +58,41 @@ public @interface Indexed {
boolean dropDups() default false;
/**
- * Index name.
+ * Index name.
+ *
+ * The name will only be applied as is when defined on root level. For usage on nested or embedded structures the
+ * provided name will be prefixed with the path leading to the entity.
+ *
+ * The structure below
+ *
+ *
+ *
+ * @Document
+ * class Root {
+ * Hybrid hybrid;
+ * Nested nested;
+ * }
+ *
+ * @Document
+ * class Hybrid {
+ * @Indexed(name="index") String h1;
+ * }
+ *
+ * class Nested {
+ * @Indexed(name="index") String n1;
+ * }
+ *
+ *
+ *
+ * resolves in the following index structures
+ *
+ *
+ *
+ * db.root.ensureIndex( { hybrid.h1: 1 } , { name: "hybrid.index" } )
+ * db.root.ensureIndex( { nested.n1: 1 } , { name: "nested.index" } )
+ * db.hybrid.ensureIndex( { h1: 1} , { name: "index" } )
+ *
+ *
*
* @return
*/
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java
index d51089a35..947a56b9a 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolver.java
@@ -25,7 +25,6 @@ import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.PropertyHandler;
@@ -96,7 +95,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
Assert.notNull(document, "Given entity is not collection root.");
final List indexInformation = new ArrayList();
- indexInformation.addAll(potentiallyCreateCompoundIndexDefinitions("", root.getCollection(), root.getType()));
+ indexInformation.addAll(potentiallyCreateCompoundIndexDefinitions("", root.getCollection(), root));
indexInformation.addAll(potentiallyCreateTextIndexDefinition(root));
final CycleGuard guard = new CycleGuard();
@@ -138,10 +137,11 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
private List resolveIndexForClass(final Class> type, final String path,
final String collection, final CycleGuard guard) {
+ MongoPersistentEntity> entity = mappingContext.getPersistentEntity(type);
+
final List indexInformation = new ArrayList();
- indexInformation.addAll(potentiallyCreateCompoundIndexDefinitions(path, collection, type));
+ indexInformation.addAll(potentiallyCreateCompoundIndexDefinitions(path, collection, entity));
- MongoPersistentEntity> entity = mappingContext.getPersistentEntity(type);
entity.doWithProperties(new PropertyHandler() {
@Override
@@ -183,14 +183,13 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
}
private List potentiallyCreateCompoundIndexDefinitions(String dotPath, String collection,
- Class> type) {
+ MongoPersistentEntity> entity) {
- if (AnnotationUtils.findAnnotation(type, CompoundIndexes.class) == null
- && AnnotationUtils.findAnnotation(type, CompoundIndex.class) == null) {
+ if (entity.findAnnotation(CompoundIndexes.class) == null && entity.findAnnotation(CompoundIndex.class) == null) {
return Collections.emptyList();
}
- return createCompoundIndexDefinitions(dotPath, collection, type);
+ return createCompoundIndexDefinitions(dotPath, collection, entity);
}
private Collection extends IndexDefinitionHolder> potentiallyCreateTextIndexDefinition(MongoPersistentEntity> root) {
@@ -278,21 +277,21 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
* @return
*/
protected List createCompoundIndexDefinitions(String dotPath, String fallbackCollection,
- Class> type) {
+ MongoPersistentEntity> entity) {
List indexDefinitions = new ArrayList();
- CompoundIndexes indexes = AnnotationUtils.findAnnotation(type, CompoundIndexes.class);
+ CompoundIndexes indexes = entity.findAnnotation(CompoundIndexes.class);
if (indexes != null) {
for (CompoundIndex index : indexes.value()) {
- indexDefinitions.add(createCompoundIndexDefinition(dotPath, fallbackCollection, index));
+ indexDefinitions.add(createCompoundIndexDefinition(dotPath, fallbackCollection, index, entity));
}
}
- CompoundIndex index = AnnotationUtils.findAnnotation(type, CompoundIndex.class);
+ CompoundIndex index = entity.findAnnotation(CompoundIndex.class);
if (index != null) {
- indexDefinitions.add(createCompoundIndexDefinition(dotPath, fallbackCollection, index));
+ indexDefinitions.add(createCompoundIndexDefinition(dotPath, fallbackCollection, index, entity));
}
return indexDefinitions;
@@ -300,13 +299,13 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
@SuppressWarnings("deprecation")
protected IndexDefinitionHolder createCompoundIndexDefinition(String dotPath, String fallbackCollection,
- CompoundIndex index) {
+ CompoundIndex index, MongoPersistentEntity> entity) {
CompoundIndexDefinition indexDefinition = new CompoundIndexDefinition(resolveCompoundIndexKeyFromStringDefinition(
dotPath, index.def()));
if (!index.useGeneratedName()) {
- indexDefinition.named(index.name());
+ indexDefinition.named(pathAwareIndexName(index.name(), dotPath, null));
}
if (index.unique()) {
@@ -377,7 +376,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
IndexDirection.ASCENDING.equals(index.direction()) ? Sort.Direction.ASC : Sort.Direction.DESC);
if (!index.useGeneratedName()) {
- indexDefinition.named(StringUtils.hasText(index.name()) ? index.name() : dotPath);
+ indexDefinition.named(pathAwareIndexName(index.name(), dotPath, persitentProperty));
}
if (index.unique()) {
@@ -419,7 +418,7 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
indexDefinition.withMin(index.min()).withMax(index.max());
if (!index.useGeneratedName()) {
- indexDefinition.named(StringUtils.hasText(index.name()) ? index.name() : persistentProperty.getName());
+ indexDefinition.named(pathAwareIndexName(index.name(), dotPath, persistentProperty));
}
indexDefinition.typed(index.type()).withBucketSize(index.bucketSize()).withAdditionalField(index.additionalField());
@@ -427,6 +426,23 @@ public class MongoPersistentEntityIndexResolver implements IndexResolver {
return new IndexDefinitionHolder(dotPath, indexDefinition, collection);
}
+ private String pathAwareIndexName(String indexName, String dotPath, MongoPersistentProperty property) {
+
+ String nameToUse = StringUtils.hasText(indexName) ? indexName : "";
+
+ if (!StringUtils.hasText(dotPath) || (property != null && dotPath.equals(property.getFieldName()))) {
+ return StringUtils.hasText(nameToUse) ? nameToUse : dotPath;
+ }
+
+ if (StringUtils.hasText(dotPath)) {
+
+ nameToUse = StringUtils.hasText(nameToUse) ? (property != null ? dotPath.replace("." + property.getFieldName(),
+ "") : dotPath) + "." + nameToUse : dotPath;
+ }
+ return nameToUse;
+
+ }
+
/**
* {@link CycleGuard} holds information about properties and the paths for accessing those. This information is used
* to detect potential cycles within the references.
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java
index 8887f9bde..815dd775d 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexCreatorUnitTests.java
@@ -163,8 +163,8 @@ public class MongoPersistentEntityIndexCreatorUnitTests {
new MongoPersistentEntityIndexCreator(mappingContext, factory);
assertThat(keysCaptor.getValue(), equalTo(new BasicDBObjectBuilder().add("company.address.location", "2d").get()));
- assertThat(optionsCaptor.getValue(), equalTo(new BasicDBObjectBuilder().add("name", "location").add("min", -180)
- .add("max", 180).add("bits", 26).get()));
+ assertThat(optionsCaptor.getValue(), equalTo(new BasicDBObjectBuilder().add("name", "company.address.location")
+ .add("min", -180).add("max", 180).add("bits", 26).get()));
}
/**
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java
index c05aec1df..2af355571 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/index/MongoPersistentEntityIndexResolverUnitTests.java
@@ -744,6 +744,60 @@ public class MongoPersistentEntityIndexResolverUnitTests {
.resolveIndexForEntity(dummy);
}
+ /**
+ * @see DATAMONGO-1025
+ */
+ @Test
+ public void shouldUsePathIndexAsIndexNameForDocumentsHavingNamedNestedCompoundIndexFixedOnCollection() {
+
+ List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNestedDocumentHavingNamedCompoundIndex.class);
+ assertThat((String) indexDefinitions.get(0).getIndexOptions().get("name"),
+ equalTo("propertyOfTypeHavingNamedCompoundIndex.c_index"));
+ }
+
+ /**
+ * @see DATAMONGO-1025
+ */
+ @Test
+ public void shouldUseIndexNameForNestedTypesWithNamedCompoundIndexDefinition() {
+
+ List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNestedTypeHavingNamedCompoundIndex.class);
+ assertThat((String) indexDefinitions.get(0).getIndexOptions().get("name"),
+ equalTo("propertyOfTypeHavingNamedCompoundIndex.c_index"));
+ }
+
+ /**
+ * @see DATAMONGO-1025
+ */
+ @Test
+ public void shouldUsePathIndexAsIndexNameForDocumentsHavingNamedNestedIndexFixedOnCollection() {
+
+ List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNestedDocumentHavingNamedIndex.class);
+ assertThat((String) indexDefinitions.get(0).getIndexOptions().get("name"),
+ equalTo("propertyOfTypeHavingNamedIndex.property_index"));
+ }
+
+ /**
+ * @see DATAMONGO-1025
+ */
+ @Test
+ public void shouldUseIndexNameForNestedTypesWithNamedIndexDefinition() {
+
+ List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNestedTypeHavingNamedIndex.class);
+ assertThat((String) indexDefinitions.get(0).getIndexOptions().get("name"),
+ equalTo("propertyOfTypeHavingNamedIndex.property_index"));
+ }
+
+ /**
+ * @see DATAMONGO-1025
+ */
+ @Test
+ public void shouldUseIndexNameOnRootLevel() {
+
+ List indexDefinitions = prepareMappingContextAndResolveIndexForType(DocumentWithNamedIndex.class);
+ assertThat((String) indexDefinitions.get(0).getIndexOptions().get("name"), equalTo("property_index"));
+ }
+
@Document
static class MixedIndexRoot {
@@ -836,6 +890,54 @@ public class MongoPersistentEntityIndexResolverUnitTests {
List cyclic;
}
+
+ @Document
+ @CompoundIndex(name = "c_index", def = "{ foo:1, bar:1 }")
+ static class DocumentWithNamedCompoundIndex {
+
+ String property;
+ }
+
+ @Document
+ static class DocumentWithNamedIndex {
+
+ @Indexed(name = "property_index") String property;
+ }
+
+ static class TypeWithNamedIndex {
+
+ @Indexed(name = "property_index") String property;
+ }
+
+ @Document
+ static class DocumentWithNestedDocumentHavingNamedCompoundIndex {
+
+ DocumentWithNamedCompoundIndex propertyOfTypeHavingNamedCompoundIndex;
+ }
+
+ @CompoundIndex(name = "c_index", def = "{ foo:1, bar:1 }")
+ static class TypeWithNamedCompoundIndex {
+ String property;
+ }
+
+ @Document
+ static class DocumentWithNestedTypeHavingNamedCompoundIndex {
+
+ TypeWithNamedCompoundIndex propertyOfTypeHavingNamedCompoundIndex;
+ }
+
+ @Document
+ static class DocumentWithNestedDocumentHavingNamedIndex {
+
+ DocumentWithNamedIndex propertyOfTypeHavingNamedIndex;
+ }
+
+ @Document
+ static class DocumentWithNestedTypeHavingNamedIndex {
+
+ TypeWithNamedIndex propertyOfTypeHavingNamedIndex;
+ }
+
}
private static List prepareMappingContextAndResolveIndexForType(Class> type) {