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

MongoDB强制将POJO的id字段重命名为_id的原因及解决方法

问题描述

我有如下一个简单的POJO类AssemblyMenuModel,其中包含名为id的字段:

public class AssemblyMenuModel {
    
    @JsonProperty("caption")
    protected String caption;

    @JsonProperty("path")
    protected String path;

    @JsonProperty("id")
    protected String id;

    @JsonProperty("name")
    protected String name;

    @JsonProperty("menus")
    protected List<AssemblyMenuModel> menus;

}

当插入该类的记录时,MongoDB会强制将id属性重命名为_id。我理解_id属性的意义,但找不到文档说明插入时id字段被重命名为_id的原因,希望得到解释。另外,是否有办法阻止这种行为?

补充信息(编辑1)

以下是用于将值插入文档map的方法:

public void setConfigValue(String cfgName, Object cfgValue) {

        System.out.println("setConfigValue :: Setting config value");
        
        if(cfgName==null || cfgName.isEmpty())return;
        
        try {
            
            Document cfgDocument=getAppConfigDoc();

            System.out.println("setConfigValue :: Config document = "+cfgDocument);
            
            if(cfgDocument!=null) {
                
                String appId=PlatformContextInfoProvider.getAppIdentifier();
                Bson filter=Filters.eq("applicationIdentifier", appId);
                
                UpdateOptions options=new UpdateOptions();
                options.upsert(false);
                
                Bson update=Updates.set("configs."+cfgName, cfgValue);
                getCollection().updateOne(filter, update, options);
                
            }//if closing
            
        }catch(Exception e) {e.printStackTrace();}
        
    }//setAppConfig closing

插入后MongoDB中的文档结构如下:
MongoDB文档结构

解答

1. 字段被重命名的原因

这并非MongoDB服务器本身的行为,而是你使用的Java驱动(或结合Jackson的序列化逻辑)的默认映射规则导致的。

MongoDB要求每个文档必须包含_id作为主键,Java驱动的默认映射策略会自动将POJO中名为id的字段映射到MongoDB的_id字段——即便你添加了@JsonProperty("id")注解,驱动内置的映射逻辑会优先识别id字段,并将其关联到_id。

2. 阻止该行为的方法

要保留原id字段名,需要明确配置映射规则,避免驱动将id默认映射到_id:

方法一:使用MongoDB原生@BsonProperty注解

如果使用MongoDB原生POJO映射,用@BsonProperty指定字段名,同时按需显式声明_id主键字段:

public class AssemblyMenuModel {
    
    @BsonProperty("caption")
    protected String caption;

    @BsonProperty("path")
    protected String path;

    // 明确指定映射到"id"字段
    @BsonProperty("id")
    protected String id;

    // 若需要MongoDB主键,单独声明_id字段
    @BsonId
    protected ObjectId _id;

    @BsonProperty("name")
    protected String name;

    @BsonProperty("menus")
    protected List<AssemblyMenuModel> menus;

}

方法二:配置Jackson的MongoDB模块

如果通过Jackson序列化POJO为Document,可禁用MongoDB模块对id字段的默认映射:

// 创建MongoDB Jackson模块并关闭自动映射规则
MongoJacksonModule module = new MongoJacksonModule();
module.setObjectIdConverter(null);

// 注册模块到ObjectMapper
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);

// 用配置好的mapper序列化对象
Document doc = mapper.convertValue(cfgValue, Document.class);
// 再执行update操作

方法三:自定义POJO映射配置

通过MongoClientSettings配置自定义POJO Codec,手动控制字段映射:

CodecRegistry pojoCodecRegistry = CodecRegistries.fromProviders(
    PojoCodecProvider.builder()
        .register(AssemblyMenuModel.class)
        .configure(MongoPojoConfiguration.builder()
            .addCustomCodec(AssemblyMenuModel.class, new CustomAssemblyMenuCodec())
            .build())
        .build());

MongoClientSettings settings = MongoClientSettings.builder()
    .codecRegistry(CodecRegistries.fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry))
    .build();

MongoClient client = MongoClients.create(settings);

自定义Codec时,手动处理字段序列化逻辑,确保id字段被映射为文档中的"id"而非"_id"。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 17:31:06