You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 08:10:33