在Nest.js中如何让Mongoose支持混合模式或多类型单Schema?
在Nest.js中实现Mongoose单集合多类型(仅存一个类结构)的方案
需求说明
你要实现的是单集合存储不同类型的文档,且每个文档仅对应One/Two/Three中的一种结构,这正好对应Mongoose的「鉴别器(Discriminators)」特性——它允许在同一个集合下使用不同Schema,通过一个鉴别字段区分文档类型,每个文档只会包含对应类型的字段。
适配Nest.js代码的实现步骤
1. 改造基础类与装饰器
首先修改SomeThing类,添加鉴别器字段,并配置discriminatorKey(指定用来区分类型的字段名):
import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose'; import { Document } from 'mongoose'; export type SomeThingDocument = SomeThing & Document; @Schema({ discriminatorKey: 'thingType' }) // 指定鉴别字段名 export class SomeThing { // 用enum限制可选类型,确保只能是三个类对应的标识 @Prop({ required: true, enum: ['one', 'two', 'three'] }) thingType: string; }
2. 定义子类(One/Two/Three)
让三个子类继承SomeThing,并为每个字段添加@Prop装饰器(Mongoose需要这个装饰器识别Schema字段):
@Schema() export class One extends SomeThing { @Prop({ required: true }) name: string; @Prop({ required: true }) type: string; } @Schema() export class Two extends SomeThing { @Prop({ required: true }) height: number; // 注:原代码中"hight"应为笔误,修正为"height" @Prop({ required: true }) depth: number; } @Schema() export class Three extends SomeThing { @Prop({ required: true }) count: number; // 用Record<string, any>替代object,类型更严谨 @Prop({ required: true, type: Object }) properties: Record<string, any>; }
3. 创建Schema与鉴别器
先创建基础的SomeThingSchema,再基于它创建三个子类的鉴别器:
// 创建基础Schema export const SomeThingSchema = SchemaFactory.createForClass(SomeThing); // 为每个子类创建鉴别器,绑定到基础Schema export const OneSchema = SomeThingSchema.discriminator('One', SchemaFactory.createForClass(One)); export const TwoSchema = SomeThingSchema.discriminator('Two', SchemaFactory.createForClass(Two)); export const ThreeSchema = SomeThingSchema.discriminator('Three', SchemaFactory.createForClass(Three));
4. 在Nest模块中注册
只需注册基础的SomeThingSchema即可,鉴别器会自动依附于它:
import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { SomeThing, SomeThingSchema } from './your-schema-file'; @Module({ imports: [ MongooseModule.forFeature([ { name: SomeThing.name, schema: SomeThingSchema }, ]), ], }) export class YourModule {}
5. 业务代码中使用
在Service中注入Model,创建不同类型的文档时指定thingType,Mongoose会自动匹配对应的鉴别器:
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { SomeThingDocument, One, Two, Three } from './your-schema-file'; @Injectable() export class YourService { constructor( @InjectModel(SomeThing.name) private thingModel: Model<SomeThingDocument>, ) {} // 创建One类型的文档 async createOne(data: Omit<One, 'thingType' | '_id'>) { const doc = new this.thingModel({ ...data, thingType: 'one' }); return doc.save(); } // 创建Two类型的文档 async createTwo(data: Omit<Two, 'thingType' | '_id'>) { const doc = new this.thingModel({ ...data, thingType: 'two' }); return doc.save(); } // 创建Three类型的文档 async createThree(data: Omit<Three, 'thingType' | '_id'>) { const doc = new this.thingModel({ ...data, thingType: 'three' }); return doc.save(); } }
效果说明
- 每个存入集合的文档只会包含对应类型的字段(比如One类型的文档只有
name/type/thingType,不会有height等字段) - 查询时,Mongoose会自动根据
thingType字段返回对应类型的文档实例 - 完全符合你“每次仅实现三个类中的一个”的需求,这就是Mongoose官方所说的混合模式的适配方案
内容的提问来源于stack exchange,提问作者Lee
相关产品推荐
相关产品推荐

