Mongoose自定义_id如何设置默认值为ObjectId,字符串_id是否有使用隐患
问题解答
实现自定义字符串_id和默认ObjectId类型_id共存的方案
你当前代码存在两个核心问题:
- 把
_id的type强制指定为String,无论默认值传入什么类型,Mongoose都会自动转为字符串存储 - 现有
default写法存在严重错误:直接调用mongoose.Types.ObjectId()会在Schema加载时生成一个固定的ObjectId,所有未手动指定_id的用户都会共用同一个_id,生产环境会直接报主键冲突错误
正确配置如下,使用Mixed混合类型支持同时存储字符串和ObjectId类型,同时将默认值改为函数形式,确保每次新建文档生成全新的ObjectId:
const userSchema = new mongoose.Schema({ _id: { type: mongoose.Schema.Types.Mixed, // 函数形式默认值,每次新建无自定义_id的文档时生成新的ObjectId default: () => new mongoose.Types.ObjectId(), required: true }, password: String, fName: String, lName: String, email: { type: String, unique: true, lowercase: true }, blogs: [blogSchema], followers: Array, followings: Array, darkMode: Boolean, });
配置完成后,手动传入字符串类型_id时会直接存储字符串,未传入时默认存储原生ObjectId类型。
默认_id使用字符串类型的潜在问题
如果坚持将默认_id设为字符串类型,会存在以下风险:
- 存储成本升高:原生ObjectId是12字节的二进制存储,转换为24位字符串后存储空间翻倍,数据量较大时会明显提升存储成本
- 查询性能下降:字符串类型的主键索引、排序性能弱于原生ObjectId,数据量超过十万级时接口响应延迟会有可感知的上升
- 兼容性问题:MongoDB原生操作、Mongoose内置方法(如
populate关联、$lookup聚合查询)默认期望_id为ObjectId类型,字符串_id会出现关联两边类型不匹配导致查询为空的问题,需要额外编写类型转换逻辑,提升代码复杂度 - 额外错误风险:即使修正默认值为动态生成字符串的写法,也可能在跨服务传参、类型校验时出现不必要的错误。
内容的提问来源于stack exchange,提问作者Luka Darsalia
相关产品推荐
相关产品推荐

