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中的文档结构如下:
解答
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
相关产品推荐
相关产品推荐

