此版本仍在开发中,尚未被视为稳定版。如需最新稳定版本,请使用 Spring Data MongoDB 5.0.4spring-doc.cadn.net.cn

索引创建

Spring Data MongoDB 可以为使用 @Document 注解的实体类型自动创建索引。 从 3.0 版本开始,必须显式启用索引创建功能,以避免对集合生命周期和性能造成不良影响。 索引会在应用程序启动时为初始实体集自动创建,并在应用程序运行期间首次访问某个实体类型时自动创建。spring-doc.cadn.net.cn

我们通常建议显式创建索引,以便应用程序能够对索引进行控制,因为 Spring Data 无法自动为在应用程序运行期间被重新创建的集合创建索引。spring-doc.cadn.net.cn

IndexResolver 提供了一种抽象机制,用于以编程方式创建索引定义,如果您希望使用 @Indexed 注解(例如 @GeoSpatialIndexed@TextIndexed@CompoundIndex@WildcardIndexed)的话。 您可以将索引定义与 IndexOperations 结合使用来创建索引。 创建索引的一个合适时机是在应用程序启动时,具体来说是在应用上下文刷新之后,这可以通过监听 ContextRefreshedEvent 事件来触发。 该事件可确保上下文已完全初始化。 请注意,在此时,其他组件(尤其是 bean 工厂)可能已经能够访问 MongoDB 数据库。spring-doc.cadn.net.cn

Map 类型的属性会被 IndexResolver 跳过,除非使用 @WildcardIndexed 注解,因为映射键(map key)必须包含在索引定义中。由于 Map 的用途是使用动态的键和值,因此无法从静态的映射元数据中解析出这些键。spring-doc.cadn.net.cn

示例 1. 为单一领域类型以编程方式创建索引
class MyListener {

  @EventListener(ContextRefreshedEvent.class)
  public void initIndicesAfterStartup() {

    MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = mongoTemplate
                .getConverter().getMappingContext();

    IndexResolver resolver = new MongoPersistentEntityIndexResolver(mappingContext);

    IndexOperations indexOps = mongoTemplate.indexOps(DomainType.class);
    resolver.resolveIndexFor(DomainType.class).forEach(indexOps::ensureIndex);
  }
}
示例2. 为所有初始实体以编程方式创建索引
class MyListener{

  @EventListener(ContextRefreshedEvent.class)
  public void initIndicesAfterStartup() {

    MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = mongoTemplate
        .getConverter().getMappingContext();

    // consider only entities that are annotated with @Document
    mappingContext.getPersistentEntities()
                            .stream()
                            .filter(it -> it.isAnnotationPresent(Document.class))
                            .forEach(it -> {

    IndexOperations indexOps = mongoTemplate.indexOps(it.getType());
    resolver.resolveIndexFor(it.getType()).forEach(indexOps::ensureIndex);
    });
  }
}

或者,如果你想在应用程序中的任何组件能够访问数据库之前确保索引和集合已存在,请为 @Bean 声明一个 MongoTemplate 方法,并在返回 MongoTemplate 对象之前加入上述代码。spring-doc.cadn.net.cn

要启用自动索引创建功能,请在您的配置中重写autoIndexCreation()方法。spring-doc.cadn.net.cn

@Configuration
public class Config extends AbstractMongoClientConfiguration {

  @Override
  public boolean autoIndexCreation() {
    return true;
  }

// ...
}
从 3.0 版本起,默认情况下自动索引创建功能已关闭

复合索引

也支持复合索引。它们在类级别上定义,而不是在单个属性上定义。spring-doc.cadn.net.cn

复合索引对于提升涉及多个字段条件的查询性能非常重要。

以下是一个示例,它创建了一个复合索引,其中 lastName 按升序排列,age 按降序排列:spring-doc.cadn.net.cn

示例 3. 复合索引使用示例
@Document
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}")
public class Person {

  @Id
  private ObjectId id;
  private Integer age;
  private String firstName;
  private String lastName;

}

@CompoundIndex 是可重复的,使用 @CompoundIndexes 作为其容器。spring-doc.cadn.net.cn

@Document
@CompoundIndex(name = "cmp-idx-one", def = "{'firstname': 1, 'lastname': -1}")
@CompoundIndex(name = "cmp-idx-two", def = "{'address.city': -1, 'address.street': 1}")
public class Person {

  String firstname;
  String lastname;

  Address address;

  // ...
}

哈希索引

哈希索引允许在分片集群内基于哈希进行分片。 使用哈希字段值对集合进行分片可实现更随机的分布。 有关详细信息,请参阅MongoDB 文档spring-doc.cadn.net.cn

以下是一个为 _id 创建哈希索引的示例:spring-doc.cadn.net.cn

示例 4. 哈希索引使用示例
@Document
public class DomainType {

  @HashIndexed @Id String id;

  // ...
}

哈希索引可以与其他索引定义一起创建,如下所示,在这种情况下,两个索引都会被创建:spring-doc.cadn.net.cn

示例5. 哈希索引与简单索引结合使用的示例
@Document
public class DomainType {

  @Indexed
  @HashIndexed
  String value;

  // ...
}

如果上面的示例过于冗长,可以使用复合注解来减少在属性上需要声明的注解数量:spring-doc.cadn.net.cn

示例6. 组合哈希索引使用示例
@Document
public class DomainType {

  @IndexAndHash(name = "idx...")                            (1)
  String value;

  // ...
}

@Indexed
@HashIndexed
@Retention(RetentionPolicy.RUNTIME)
public @interface IndexAndHash {

  @AliasFor(annotation = Indexed.class, attribute = "name") (1)
  String name() default "";
}
1 可能为元注解的某些属性注册一个别名。

尽管通过注解创建索引在许多场景下非常方便,但建议通过 IndexOperations 手动设置索引,以获得更精细的控制。spring-doc.cadn.net.cn

mongoOperations.indexOpsFor(Jedi.class)
  .ensureIndex(HashedIndex.hashed("useTheForce"));

通配符索引

WildcardIndex 是一种索引,可用于包含所有字段或基于给定(通配符)模式的特定字段。 有关详细信息,请参阅 MongoDB 文档spring-doc.cadn.net.cn

可以通过 WildcardIndex 使用 IndexOperations 以编程方式设置索引。spring-doc.cadn.net.cn

示例 7. 以编程方式设置 WildcardIndex
mongoOperations
    .indexOps(User.class)
    .ensureIndex(new WildcardIndex("userMetadata"));
db.user.createIndex({ "userMetadata.$**" : 1 }, {})

@WildcardIndex 注解允许以声明式的方式设置索引,可用于文档类型或属性。spring-doc.cadn.net.cn

如果放置在根级别的领域实体类型(即带有 @Document 注解的类)上,索引解析器将为其创建一个通配符索引。spring-doc.cadn.net.cn

示例 8. 域类型上的通配符索引
@Document
@WildcardIndexed
public class Product {
	// …
}
db.product.createIndex({ "$**" : 1 },{})

wildcardProjection 可用于指定在索引中包含或排除的键。spring-doc.cadn.net.cn

示例 9. 使用 wildcardProjection 的通配符索引
@Document
@WildcardIndexed(wildcardProjection = "{ 'userMetadata.age' : 0 }")
public class User {
    private @Id String id;
    private UserMetadata userMetadata;
}
db.user.createIndex(
  { "$**" : 1 },
  { "wildcardProjection" :
    { "userMetadata.age" : 0 }
  }
)

通配符索引也可以通过直接在字段上添加注解来表示。 请注意,wildcardProjection 不允许用于嵌套路径(例如属性)。 在创建索引时,会忽略对带有 @WildcardIndexed 注解的类型所设置的投影。spring-doc.cadn.net.cn

示例 10. 属性上的通配符索引
@Document
public class User {
    private @Id String id;

    @WildcardIndexed
    private UserMetadata userMetadata;
}
db.user.createIndex({ "userMetadata.$**" : 1 }, {})

文本索引

MongoDB v2.4 默认禁用了文本索引功能。

创建文本索引可以将多个字段聚合到一个可搜索的全文索引中。 每个集合只能拥有一个文本索引,因此所有标记了 @TextIndexed 的字段都会被合并到该索引中。 可以为属性设置权重,以影响文档评分,从而对搜索结果进行排序。 文本索引的默认语言是英语。要更改默认语言,请将 language 属性设置为您所需的语言(例如,@Document(language="spanish"))。 通过使用名为 language 的属性或 @Language 注解,您可以为每个文档单独指定语言覆盖。 以下示例展示了如何创建文本索引并将语言设置为西班牙语:spring-doc.cadn.net.cn

示例 11. 示例文本索引用法
@Document(language = "spanish")
class SomeEntity {

    @TextIndexed String foo;

    @Language String lang;

    Nested nested;
}

class Nested {

    @TextIndexed(weight=5) String bar;
    String roo;
}