NestJS Mongoose 模式继承

Posted

技术标签:

【中文标题】NestJS Mongoose 模式继承【英文标题】:NestJS Mongoose Schema Inheritence 【发布时间】:2021-11-15 06:02:32 【问题描述】:

我正在尝试在 NestJS 中继承 Mongoose Schemas 或 SchemaDefitions,但我运气不佳。 我这样做是为了可以共享基本和通用模式定义详细信息,例如虚拟('id')和随机数,我们已附加到每个实体。每个模式定义在 Mongo 中都应该有自己的集合,因此鉴别器不起作用。

我尝试通过以下不同的方式实现这一点

首先,我定义了以下基本架构定义:

base.schema.ts

import  Prop, Schema, SchemaFactory  from '@nestjs/mongoose';
import  Document, Types  from 'mongoose';
import  TimeStamps  from './timestamps.schema';

export type BaseDocument = BaseSchemaDefinition & Document;

@Schema(
  toJSON: 
    virtuals: true,
    transform: function (doc: any, ret: any) 
      delete ret._id;
      delete ret.__v;
      return ret;
    ,
  ,
)
export class BaseSchemaDefinition 
  @Prop(
    type: Types.ObjectId,
    required: true,
    default: Types.ObjectId,
  )
  nonce: Types.ObjectId;

  @Prop()
  timestamps: TimeStamps;

然后我继承架构定义并创建架构,以便以后可以通过以下方式在我的服务和控制器中使用它:

person.schema.ts

import  Prop, SchemaFactory  from '@nestjs/mongoose';
import * as mongoose from 'mongoose';
import  Document  from 'mongoose';
import  Address  from './address.schema';
import  BaseSchemaDefinition  from './base.schema';

export type PersonDocument = PersonSchemaDefintion & Document;

export class PersonSchemaDefintion extends BaseSchemaDefinition 
  @Prop( required: true )
  first_name: string;

  @Prop( required: true )
  last_name: string;

  @Prop()
  middle_name: string;

  @Prop()
  data_of_birth: Date;

  @Prop( type: [ type: mongoose.Schema.Types.ObjectId, ref: 'Address' ] )
  addresses: [Address];


const PersonSchema = SchemaFactory.createForClass(PersonSchemaDefintion);

PersonSchema.virtual('id').get(function (this: PersonDocument) 
  return this._id;
);

export  PersonSchema ;

这导致只允许我创建和获取在 BaseSchemaDefinition 中定义的属性。

时间戳”: “已删除”:空, “更新”:“2021-09-21T16:55:17.094Z”, “创建”:“2021-09-21T16:55:17.094Z” , "_id": "614a0e75eb6cb52aa0ccd026", “随机数”:“614a0e75eb6cb52aa0ccd028”, "__v": 0

其次,我然后尝试使用这里描述的方法来实现继承 Inheriting Mongoose schemas(不同的 MongoDB 集合)

base.schema.ts

import  Prop, Schema, SchemaFactory  from '@nestjs/mongoose';
import  Document, Types  from 'mongoose';
import  TimeStamps  from './timestamps.schema';

export type BaseDocument = BaseSchemaDefinition & Document;

@Schema(
  toJSON: 
    virtuals: true,
    transform: function (doc: any, ret: any) 
      delete ret._id;
      delete ret.__v;
      return ret;
    ,
  ,
)
export class BaseSchemaDefinition 
  @Prop(
    type: Types.ObjectId,
    required: true,
    default: Types.ObjectId,
  )
  nonce: Types.ObjectId;

  @Prop()
  timestamps: TimeStamps;


const BaseSchema = SchemaFactory.createForClass(BaseSchemaDefinition);

BaseSchema.virtual('id').get(function (this: BaseDocument) 
  return this._id;
);

export  BaseSchema ;

person.schema.ts

import  Prop  from '@nestjs/mongoose';
import * as mongoose from 'mongoose';
import  Document  from 'mongoose';
import  Address  from './address.schema';
import  BaseSchema, BaseSchemaDefinition  from './base.schema';

export type PersonDocument = PersonSchemaDefintion & Document;

export class PersonSchemaDefintion extends BaseSchemaDefinition 
  @Prop( required: true )
  first_name: string;

  @Prop( required: true )
  last_name: string;

  @Prop()
  middle_name: string;

  @Prop()
  data_of_birth: Date;

  @Prop( type: [ type: mongoose.Schema.Types.ObjectId, ref: 'Address' ] )
  addresses: [Address];


export const PersonSchema = Object.assign(
  ,
  BaseSchema.obj,
  PersonSchemaDefintion,
);

产生相同的输出。不知道为什么没有继承

以下是使用模式和构建模型的服务代码

person.service.ts

import  Model  from 'mongoose';
import  Injectable  from '@nestjs/common';
import  InjectModel  from '@nestjs/mongoose';
import 
  PersonSchemaDefintion,
  PersonDocument,
 from 'src/schemas/person.schema';
import  TimeStamps  from 'src/schemas/timestamps.schema';

@Injectable()
export class PersonService 
  constructor(
    @InjectModel(PersonSchemaDefintion.name)
    private personModel: Model<PersonDocument>,
  ) 

  async create(
    personModel: PersonSchemaDefintion,
  ): Promise<PersonSchemaDefintion> 
    personModel.timestamps = new TimeStamps();
    const createdPerson = new this.personModel(personModel);

    return createdPerson.save();
  

  async update(
    id: string,
    changes: Partial<PersonSchemaDefintion>,
  ): Promise<PersonSchemaDefintion> 
    const existingPerson = this.personModel
      .findByIdAndUpdate(id, changes)
      .exec()
      .then(() => 
        return this.personModel.findById(id);
      );
    if (!existingPerson) 
      throw Error('Id does not exist');
    
    return existingPerson;
  

  async findAll(): Promise<PersonSchemaDefintion[]> 
    return this.personModel.find().exec();
  

  async findOne(id: string): Promise<PersonSchemaDefintion> 
    return this.personModel.findById(id).exec();
  

  async delete(id: string): Promise<string> 
    return this.personModel.deleteOne( _id: id ).then(() => 
      return Promise.resolve(`$id has been deleted`);
    );
  

如果需要,我可以提供更多详细信息

【问题讨论】:

【参考方案1】:

在摆弄了一段时间后,我发现了在利用这些技术时似乎可行的正确组合

这是基类

base.schema.ts

import  Prop, Schema  from '@nestjs/mongoose';
import  Document, Types  from 'mongoose';
import  TimeStamps  from './timestamps.schema';

export type BaseDocument = Base & Document;

@Schema()
export class Base 
  @Prop(
    type: Types.ObjectId,
    required: true,
    default: Types.ObjectId,
  )
  nonce: Types.ObjectId;

  @Prop()
  timestamps: TimeStamps;

这里是继承base.schema的类

person.schema.ts

import  Prop, Schema, SchemaFactory  from '@nestjs/mongoose';
import  Document, Types  from 'mongoose';
import  Address  from './address.schema';
import  Base  from './base.schema';

export type PersonDocument = Person & Document;

@Schema(
  toJSON: 
    virtuals: true,
    transform: function (doc: any, ret: any) 
      delete ret._id;
      delete ret.__v;
      return ret;
    ,
  ,
)
export class Person extends Base 
  @Prop( required: true )
  first_name: string;

  @Prop( required: true )
  last_name: string;

  @Prop()
  middle_name: string;

  @Prop()
  data_of_birth: Date;

  @Prop( type: [ type: Types.ObjectId, ref: 'Address' ] )
  addresses: [Address];

const PersonSchema = SchemaFactory.createForClass(Person);

PersonSchema.virtual('id').get(function (this: PersonDocument) 
  return this._id;
);

export  PersonSchema ;

我唯一想改进的是将 virtual('id') 移至基类。但是模式继承不起作用。此时,它只适用于模式定义。这至少让我朝着正确的方向前进。如果有人有办法改进这一点,请贡献。

【讨论】:

以上是关于NestJS Mongoose 模式继承的主要内容,如果未能解决你的问题,请参考以下文章

NestJS + Mongoose:如何测试 document(data).save()?

NestJs / Mongoose 在 Docker 撰写时无法建立 MongoDB 数据库连接

mongoose @prop() 装饰器类型:模式定义中的对象_NestJS

如何引用我试图保存在 nestjs/mongoose 中的模式?

NestJS/Mongoose - 参考另一个模式创建一个对象数组

如何在@nestjs/mongoose 模式中设置枚举