如何仅获取Mongoose鉴别器基模型的字段?
如何强制Mongoose仅返回基模型User的字段?
我们系统中有一个面向所有用户的基模型User,还有一个Self模型用于存储仅当前用户可访问的私有属性(如邮箱地址)。Self是继承自User的Mongoose鉴别器:
const userSchema = new mongoose.Schema<IMongooseUser>({ username: String, ... }); export const User = mongoose.model('User', userSchema); const selfSchema = new mongoose.Schema<IMongooseSelf>({ email: String, ... }); export const Self = User.discriminator('Self', selfSchema);
数据库中所有用户的__t字段值均为Self,因此使用User.findOne()查询时会同时返回Self的所有字段。以下是几种比手动设置__t更优的解决方案:
方案1:查询时显式指定投影字段
直接在查询语句中选择User模型定义的公共字段,或者排除Self的私有字段:
// 方式1:只选取需要的公共字段 const publicUser = await User.findOne({ _id: userId }).select('username'); // 方式2:排除私有字段和鉴别器标识__t const publicUser = await User.findOne({ _id: userId }).select('-email -__t');
这种方式简单直接,适合单次查询场景,能精准控制返回内容。
方案2:在Schema中设置字段默认隐藏
给Self模型的私有字段添加select: false配置,让这些字段默认不被查询返回:
const selfSchema = new mongoose.Schema<IMongooseSelf>({ email: { type: String, select: false }, // 其他私有字段同理添加select: false }); export const Self = User.discriminator('Self', selfSchema);
需要获取私有字段时,再通过+前缀显式指定:
// 仅当前用户访问时,获取包含邮箱的完整信息 const privateUser = await Self.findOne({ _id: userId }).select('+email');
方案3:用transform自动过滤字段
在User模型的Schema中配置toJSON和toObject的transform函数,自动删除私有字段:
const userSchema = new mongoose.Schema<IMongooseUser>({ username: String, ... }, { toJSON: { transform(doc, ret) { // 删除不需要的私有字段和鉴别器标识 delete ret.email; delete ret.__t; return ret; } }, toObject: { transform(doc, ret) { delete ret.email; delete ret.__t; return ret; } } }); export const User = mongoose.model('User', userSchema);
这样当你把文档转为JSON(比如在Express接口中直接返回)或者转为普通对象时,会自动过滤掉指定字段。
方案4:定义公共数据传输对象(DTO)
创建一个专门的类来提取公共字段,适合复杂场景下的字段映射和处理:
class PublicUserDTO { constructor(user) { this.username = user.username; // 按需添加其他公共字段 } } // 使用示例 const user = await User.findOne({ _id: userId }).lean(); const publicUser = new PublicUserDTO(user);
内容的提问来源于stack exchange,提问作者András Geiszl
相关产品推荐
相关产品推荐

