我有一个像这样定义的 Contract 类:
@Document
public class Contract {
@Id
private String id;
@Indexed(unique = true)
private String ref;
private String status = "pending";
// getter & setter & hashcode & equals & tostring...
}
我想随着时间的推移保存合约状态,所以我创建了一个像这样的 Version 类:
@Document
public class Version {
@Id
private String id;
private Contract contract;
private Instant createdAt;
// getter & setter & hashcode & equals & tostring...
}
当我尝试随着时间的推移多次保存版本对象时,出现重复键异常。我认为这是合同参考上重复的关键索引,在这里抱怨。
我怎样才能实现这样的目标?
只需添加@Reference,如下所示:
@Document
public class Version {
@Id
private String id;
@Reference
private Contract contract;
private Instant createdAt;
// getter & setter & hashcode & equals & tostring...
}
我不确定是否有办法从 spring 上下文中实现这一点。
最好的方法是删除代码之外的所有索引定义。即通过离线脚本应用。您可以使用 mongeez 等工具应用脚本。它可以配置为在应用程序启动时运行,因此您可以确保它始终运行,无论位置如何。
应用程序上线后,我们可能希望以受控方式构建新索引。嵌入代码可能不会带来这种优势,因为它只会在启动时运行。
如果您使用离线脚本,您就可以完全控制。
我认为你可以使用 eventListener 来创建索引,所以我使用这段代码并成功地没有在嵌入文档上创建索引,你可以尝试这个
@EventListener(ContextRefreshedEvent.class)
public void initIndicesAfterStartup() {
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext = mongoTemplate
.getConverter().getMappingContext();
IndexResolver resolver = new MongoPersistentEntityIndexResolver(mappingContext);
// consider only entities that are annotated with @Document
mappingContext.getPersistentEntities()
.stream()
.filter(it -> it.isAnnotationPresent(Document.class))
.forEach(it -> {
var indexOps = mongoTemplate.indexOps(it.getType());
resolver.resolveIndexFor(it.getType()).forEach(indexDefinition -> {
var indexHolder = (MongoPersistentEntityIndexResolver.IndexDefinitionHolder) indexDefinition;
if (StringUtils.isBlank(indexHolder.getPath())) {
indexOps.ensureIndex(indexDefinition);
}
});
});
}
这段代码的结论
var indexHolder = (MongoPersistentEntityIndexResolver.IndexDefinitionHolder) indexDefinition;
var indexHolder = (MongoPersistentEntityIndexResolver.IndexDefinitionHolder)indexDefinition;
当我们尝试嵌入文档时,不知何故在该字段上使用了indexHolder.getPath()