本文描述了@Indexed注解 “未生效” 原因以及解决方案。
首先在这里明确一下知识点:只有当
@Document
和 @Indexed同时存在
,使用mongoTemplate 或者 mongoRepository
传入
打了@Document注解的对象
时 才会自动创建索引
先上代码 ,下面的 “异常” 代码是否会自动创建索引呢?
//订单doc
@Data
@Accessors(chain = true)
@FieldNameConstants
@Document(collection = "order_")
public class Order implements Serializable {
private String id;
@Indexed
private String tid;
@Indexed
private String tradeId;
private String status;
private String created;
//使用mongoTemplate做插入操作,按照月份分表
mongoTemplate.insert(orderRecord, mongoTemplate.getCollectionName(Order.class) + month);
答案是 :会的!
那为什么说是异常代码呢,因为它没有达到我的预期,这段代码会有两个问题:
1、会在mongodb里边创建两个 collection : order_ 和 order_${month}
2、索引会创建在 “order_” 这个collection里边,而不会在 “order_${month}”
这个时候答案就很明显了:
自动创建索引的时候 ,读取的collectionName 是 @Document注解里边的值,而不是 insert的时候传入的值
。
结论已经有了,就该看看它是怎么把传入的 collectionName弄丢的了
通过debug可以找到创建索引相关类以及方法的调用路径:
这个是方法签名:
checkForIndexes((MongoPersistentEntity<?>) entity)
;
最终只剩下了entity。通过entity的@Document注解来获取collectionName。细节就不贴图了,建议去debug下看看源码。
原因找到了,最终要如何解决当前的问题呢?上代码:
//字段索引
IndexOperations indexOps2 = mongoTemplate.indexOps(orderCollectionName);
String[] indexFields2 = Arrays.stream(Order.class.getDeclaredFields())
.filter(f -> f.isAnnotationPresent(Indexed.class))
.map(Field::getName)
.toArray(String[]::new);
for (String indexField : indexFields2) {
if (StringUtils.hasText(indexField)) {
indexOps2.ensureIndex(new Index(indexField, Sort.Direction.ASC));
至此,问题解决。
最后提醒,别忘了把@Document注解去掉。原因文中已经说明。