Mongoose v6/v7中自定义'id'虚拟属性为何返回String而非ObjectId?
Mongoose v6/v7中自定义'id'虚拟属性返回String而非ObjectId的解决方法
问题描述
我有一个使用Mongoose v5的Node.js项目,升级到Mongoose v6后发现自定义的id虚拟属性不再返回ObjectId,而是变成了String。进一步排查后确认,这个问题只出现在名为id的虚拟属性上。
最小复现代码
user.js
const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({ name: String, }); userSchema.virtual('id').get(function() { return this._id; }); module.exports = mongoose.model('User', userSchema);
index.js
const mongoose = require('mongoose'); const UserModel = require('./user'); async function main() { let dbUrl = 'mongodb://username:password@localhost/assess?authSource=admin&directConnection=true'; await mongoose.connect(dbUrl); let user = await new UserModel({ name: 'Jim' }); console.log(`in Mongoose v${mongoose.version}, user.id has type ${user.id.constructor.name}`); await mongoose.disconnect(); } main();
版本输出差异
$ npm i mongoose@5 $ node index.js in Mongoose v5.13.17, user.id has type ObjectID $ npm i mongoose@6 $ node index.js in Mongoose v6.11.2, user.id has type String $ npm i mongoose@7 $ node index.js in Mongoose v7.2.4, user.id has type String
尽管虚拟属性的get函数明确返回this._id(ObjectId类型),但在v6和v7中返回值被自动转为String,需要阻止这种转换。
原因分析
Mongoose从v6开始,默认给所有文档添加了内置的id虚拟属性,该属性会自动将_id转换为String类型。自定义的id虚拟属性会被Mongoose的内置实现覆盖,导致最终返回String而非预期的ObjectId。
解决方法
方法1:禁用内置的id虚拟属性
在定义Schema时,通过id: false配置项关闭Mongoose内置的id虚拟属性,这样自定义的id虚拟属性就能正常返回ObjectId:
const userSchema = new mongoose.Schema({ name: String, }, { id: false }); // 添加该选项关闭内置id虚拟属性 userSchema.virtual('id').get(function() { return this._id; });
方法2:重命名自定义虚拟属性
如果需要保留内置的id属性(用于获取String类型的ID),可以将自定义的虚拟属性重命名,比如objectId:
userSchema.virtual('objectId').get(function() { return this._id; });
之后通过user.objectId即可获取到ObjectId类型的ID值。
内容的提问来源于stack exchange,提问作者Joel Harris
相关产品推荐
相关产品推荐

