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

MongoDB执行upsert时因修改_id字段报错的问题求助

解决MongoDB Upsert时_id字段不可修改的报错问题

这个报错的核心原因很明确:MongoDB的_id字段是文档的主键,一旦创建就不允许修改,而你的代码和实体类映射出现了冲突。

问题根源分析

在Spring Data MongoDB中,实体类里的id字段默认会自动映射到MongoDB文档的_id字段。你在代码中执行了update.set("id", String.valueOf(partnerId)),这相当于试图修改文档的_id值,直接触发了MongoDB的主键不可修改限制,所以抛出了错误。

两种可行的解决方案

方案一:让partnerId作为文档的主键(推荐)

既然你是用partnerId作为upsert的匹配条件,完全可以把partnerId设为MongoDB文档的_id,这样既符合业务逻辑,又避免了额外的id字段冲突。

修改你的PartnerAppIds实体类:

public class PartnerAppIds {
    @Id // 指定该字段为MongoDB文档的_id主键
    private Long partnerId;
    @Indexed private Set<String> appIds;

    public Long getPartnerId() { return partnerId; }
    public void setPartnerId(Long partnerId) { this.partnerId = partnerId; }
    public Set<String> getAppIds() { return appIds; }
    public void setAppIds(Set<String> appIds) { this.appIds = appIds; }
}

然后简化你的upsert代码,去掉修改id的操作:

final Update update = new Update();
update.pushAll("appIds", appIds.toArray());
mongoTemplate.upsert(Query.query(Criteria.where("partnerId").is(partnerId)), update, PartnerAppIds.class);

方案二:保留原实体结构,但禁止在Update中修改id

如果你需要保留id字段(比如它有其他业务用途),只需要删除代码中修改id的那一行即可:

final Update update = new Update();
// 删掉这一行:update.set("id", String.valueOf(partnerId));
update.pushAll("appIds", appIds.toArray());
mongoTemplate.upsert(Query.query(Criteria.where("partnerId").is(partnerId)), update, PartnerAppIds.class);

注意:如果是执行upsert中的插入操作(文档不存在时),Spring Data MongoDB会自动为id字段生成唯一值,你也可以在插入前手动给实体设置id值,但绝对不能在Update操作中修改它。

关键提示

MongoDB的_id字段是文档的唯一标识,具有不可变性,这是MongoDB的核心规则。在使用Spring Data MongoDB时,一定要注意实体类字段和_id的映射关系,避免出现类似的修改主键操作。

内容的提问来源于stack exchange,提问作者user3742525

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:13:40