Mongoose中如何实现多Schema枚举字段并设置默认值
Mongoose 实现字段匹配多Schema之一并设置默认值的方案
你原写法不生效的核心原因有两个:
enum校验规则仅支持字符串、数字、布尔值这类原始值枚举,无法直接接收Schema实例作为可选值Mixed类型是无结构的任意类型,Mongoose不会对其做任何子结构校验、转换处理
方案1:使用子文档鉴别器(Discriminator,官方推荐)
这是Mongoose原生支持多类型子文档的标准实现,自带结构校验、类型转换、默认值、子文档方法等完整能力。
实现代码如下:
const fooSchema = new mongoose.Schema({ // 填写foo的字段定义,例如: name: String, fooAttr: { type: Number, default: 0 } }); const barSchema = new mongoose.Schema({ // 填写bar的字段定义,例如: title: String, barAttr: Boolean }); const modelSchema = new mongoose.Schema({ field: { // 先定义通用子文档配置,指定鉴别器键,是否关闭自动生成_id可按需调整 type: new mongoose.Schema({}, { discriminatorKey: 'docType', _id: false }), required: true, // 默认值返回对应foo类型的标识,Mongoose会自动套用fooSchema的默认值规则 default: () => ({ docType: 'Foo' }) } }); const MyModel = mongoose.model('MyModel', modelSchema); // 给field路径注册两个可选的子文档类型 MyModel.schema.path('field').discriminator('Foo', fooSchema); MyModel.schema.path('field').discriminator('Bar', barSchema);
使用时只要传入带docType字段的对象,Mongoose会自动匹配对应Schema做校验和处理:
// 自动按fooSchema校验、填充默认值 const doc1 = await MyModel.create({ field: { docType: 'Foo', name: 'test' } }); // 自动按barSchema校验 const doc2 = await MyModel.create({ field: { docType: 'Bar', title: 'bar', barAttr: true } });
方案2:自定义校验器(轻量场景适用)
如果不需要子文档的高级特性,仅需要限制字段结构符合两个Schema之一,可以给Mixed类型加自定义校验规则:
// 提前写好两个Schema的结构判断逻辑,可根据字段必填、类型规则自行实现 function matchFooSchema(val) { return typeof val?.name === 'string' && typeof val?.fooAttr === 'number'; } function matchBarSchema(val) { return typeof val?.title === 'string' && typeof val?.barAttr === 'boolean'; } const modelSchema = new mongoose.Schema({ field: { type: mongoose.Schema.Types.Mixed, required: true, // 默认值直接写fooSchema对应的默认对象结构 default: () => ({ name: '', fooAttr: 0 }), validate: { validator: v => matchFooSchema(v) || matchBarSchema(v), message: 'field结构必须符合foo或bar的定义规则' } } });
这个方案需要自行实现所有结构校验逻辑,没有原生的类型转换、默认值自动填充能力,仅适合结构非常简单的场景。
注意事项
- 不要直接把Schema实例作为
default值传入,Schema是构造函数,存入数据库时会序列化为异常值,默认值必须是符合对应结构的普通JS对象,或者返回普通对象的函数 - 如果需要在数组字段中实现多类型子文档,鉴别器方案同样适用,注册鉴别器时改为数组对应路径即可
内容的提问来源于stack exchange,提问作者Jared Parker
相关产品推荐
相关产品推荐

