Spring Boot项目中MongoDB重复键异常(designers.username)解决方法
问题描述
我的实体类定义如下:
@Getter @Document(collection = "team") @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Team extends BaseTimeEntity { .... private List<User> designers = new ArrayList<>(); .... }
该类继承的BaseTimeEntity定义如下:
@Getter public abstract class BaseTimeEntity { @MongoId private ObjectId id; @CreatedDate @Field(name = "created_date") private LocalDateTime createdDate; @LastModifiedDate @Field(name = "modified_date") private LocalDateTime modifiedDate; @Field(name = "is_deleted") protected Boolean isDeleted; @Field(name = "schema_version") protected String schemaVersion = "1.0"; }
向数据库中添加一条Team数据后,当我尝试创建另一个designers列表为空的Team数据时,抛出了org.springframework.dao.DuplicateKeyException异常。
具体错误信息如下:
org.springframework.dao.DuplicateKeyException: Write operation error on server localhost:27017. Write error: WriteError{code=11000, message='E11000 duplicate key error collection: gabojait.team index: designer.username dup key: { designer.username: null }', details={}}.; nested exception is com.mongodb.MongoWriteException: Write operation error on server localhost:27017. Write error: WriteError{code=11000, message='E11000 duplicate key error collection: gabojait.team index: designer.username dup key: { designer.username: null }', details={}}.
请问如何解决该问题?
解决方案
问题核心是MongoDB的唯一索引特性:默认情况下,唯一索引仅允许一条文档包含该字段的null值。当Team的designers为空列表时,对应designer.username字段在MongoDB中被视为null,第二条空列表的Team插入时就会触发重复键冲突。以下是几种解决方式:
1. 修改唯一索引,允许多个null值
方式1:创建稀疏索引(Sparse Index)
执行MongoDB命令,让索引仅包含存在目标字段的文档,空列表的Team不会被纳入索引:
db.team.createIndex( { "designers.username": 1 }, { unique: true, sparse: true } )
方式2:创建部分索引(Partial Index)
MongoDB 3.2+版本支持,精准指定索引覆盖的文档范围,仅对designers.username存在且非null的文档创建唯一索引:
db.team.createIndex( { "designers.username": 1 }, { unique: true, partialFilterExpression: { "designers.username": { $exists: true, $ne: null } } } )
2. 移除不必要的唯一索引
如果业务不需要designers.username的唯一约束,直接删除该索引即可:
# 先通过以下命令查看索引名称 db.team.getIndexes() # 替换为实际索引名称执行删除 db.team.dropIndex("designers.username_1")
3. 代码层面调整(可选)
若业务允许,可修改实体类,在designers无数据时将其设为null而非空列表,但此方式需结合索引配置才能生效,并非最优解。
内容的提问来源于stack exchange,提问作者gs97ahn
相关产品推荐
相关产品推荐

