Reference Nest.js中的Mongoose子文档
我正在将我的应用程序从express.js移到Nest.js,如果不使用mongoose.Schema({…})声明模式的旧方法,我就找不到在另一个模式中引用一个mongoose模式的方法 让我们使用文档中的示例,这样我可以澄清我的问题:Reference Nest.js中的Mongoose子文档,reference,schema,nestjs,subdocument,Reference,Schema,Nestjs,Subdocument,我正在将我的应用程序从express.js移到Nest.js,如果不使用mongoose.Schema({…})声明模式的旧方法,我就找不到在另一个模式中引用一个mongoose模式的方法 让我们使用文档中的示例,这样我可以澄清我的问题: @Schema() 导出类Cat扩展文档{ @支柱( 名称:字符串; } export const CatSchema=SchemaFactory.createForClass(Cat); 现在,我想要的是这样的: @Schema() 导出类所有者扩展文档{
@Schema()
导出类Cat扩展文档{
@支柱(
名称:字符串;
}
export const CatSchema=SchemaFactory.createForClass(Cat);
现在,我想要的是这样的:
@Schema()
导出类所有者扩展文档{
@属性({type:[Cat],必需:true})
猫:猫[];
}
export const OwnerSchema=SchemaFactory.createForClass(所有者);
当我以这种方式定义模式时,会出现如下错误:模式配置无效:Cat
不是有效的模式配置
在数组中键入cats
那么,使用这种面向对象的方法来定义模式,在另一个模式中引用一个模式的正确方法是什么呢?我深入研究了源代码,了解了SchemaFactory.createForClass方法如何转换模式类 那么它是如何工作的呢? 1.请看下面的示例:
@Schema()
导出类Cat扩展文档{
@支柱(
名称:字符串;
}
export const catSchema=SchemaFactory.createForClass(Cat);
基本上,当您执行SchemaFactory.createForClass(Cat)
Nest将类语法转换为Mongoose模式语法,因此最终,转换的结果如下:
const schema=newmongoose.schema({
名称:{type:String}//请注意,'String'现在是大写的。
});
2.转换是如何工作的?
请查看此文件:
导出函数属性(选项?:属性选项):属性编辑器{
返回(目标:对象,属性key:string | symbol)=>{
options=(options |{})作为mongoose.SchemaTypeOpts;
const isRawDefinition=选项[原始对象定义];
如果(!options.type&&!Array.isArray(options)&!isRawDefinition){
const type=Reflect.getMetadata(type\u METADATA\u KEY、target、propertyKey);
if(类型===数组){
options.type=[];
}else if(type&&type!==对象){
options.type=类型;
}
}
TypeMetadataStorage.addPropertyMetadata({
target:target.constructor,
propertyKey:propertyKey作为字符串,
选项,
});
};
}
在这里,您可以看到Prop()
decorator在幕后做了什么。
当您这样做时:
@Prop()
名称:字符串;
Prop
函数将被调用,在这种情况下不带参数
const type=Reflect.getMetadata(type\u METADATA\u KEY、target、propertyKey);
使用Reflect
API,我们可以获得执行name:string
操作时使用的数据类型。type
变量的值现在设置为String
。请注意,它不是字符串
,反射
API将始终返回数据类型的构造函数版本,因此:
将被序列化为number
number
将被序列化为string
string
将被序列化为boolean
boolean
- 等等
TypeMetadataStorage.addPropertyMetadata
然后将下面的对象存储到存储中
{
目标:用户,
propertyKey:'名称',
选项:{type:String}
}
让我们看一下:
导出类TypeMetadataStorage主机{
私有模式=新数组();
私有属性=新数组();
addPropertyMetadata(元数据:PropertyMetadata){
this.properties.push(元数据);
}
}
因此基本上,该对象将存储到typeMetadataStorage主机
中的properties
变量中。
TypeMetadataStorageHost
是一个将存储大量这些对象的单例
3.模式生成
要了解SchemaFactory.createForClass(Cat)
如何生成Mongoose模式,请查看以下内容:
导出类SchemaFactory{
静态createForClass(目标:类型){
const schemaDefinition=DefinitionsFactory.createForClass(目标);
常量schemaMetadata=TypeMetadataStorage.getSchemaMetadataByTarget(
目标,,
);
返回新的mongoose.Schema(
方案定义,
schemaMetadata&&schemaMetadata.options,
);
}
}
最重要的部分是:
const schemaDefinition=DefinitionsFactory.createForClass(目标)代码>。注意,这里的目标是您的Cat
类
您可以在此处看到方法定义:
导出类定义工厂{
静态createForClass(目标:类型):mongoose.SchemaDefinition{
设schemaDefinition:mongoose.schemaDefinition={};
schemaMetadata.properties?.forEach((项)=>{
const options=this.inspectTypeDefinition(item.options,如有);
模式定义={
[item.propertyKey]:任何选项,
…方案定义,
};
});
返回模式定义;
}
schemaMetadata.properties
包含执行TypeMetadataStorage.addPropertyMetadata
操作时存储的对象:
[
{
目标:用户,
propertyKey:'名称',
选项:{type:String}
}
]
forEach
将产生:
{
名称:{type:String}
}
最后,它将被用作mongoose.Schema
构造函数的参数:
返回新的mongoose.Schema(
方案定义,
schemaMetadata&&schemaMetadata.options,
);
4.因此,要回答这个问题:
您应该将什么作为Prop()
参数
还记得什么时候嵌套forEach来生成Mongoose模式吗
schemaMetadata.properties?.forEach((项)=>{
常量选项
import { Prop, raw, Schema, SchemaFactory } from '@nestjs/mongoose';
import * as mongoose from 'mongoose';
import { Education } from '../../education/schemas';
import { RECORD_STATUS } from '../../common/common.constants';
import { Employment } from '../../employment/schemas';
import {
JOB_SEARCH_STATUS,
LANGUAGE_PROFICIENCY
} from '../user-profile.constants';
const externalLinks = {
linkedInUrl: { type: String },
githubUrl: { type: String },
twitterUrl: { type: String },
blogUrl: { type: String },
websiteUrl: { type: String },
stackoverflowUrl: { type: String }
};
const address = {
line1: { type: String, required: true },
line2: { type: String },
zipCode: { type: String },
cityId: { type: Number },
countryId: { type: Number }
};
const language = {
name: { type: String, require: true },
code: { type: String, required: true },
proficiency: { type: String, required: true, enum: LANGUAGE_PROFICIENCY }
};
const options = {
timestamps: true,
};
export type UserProfileDocument = UserProfile & mongoose.Document;
@Schema(options)
export class UserProfile {
_id: string;
@Prop()
firstName: string;
@Prop()
lastName: string;
@Prop()
headline: string;
@Prop({
unique: true,
trim: true,
lowercase: true
})
email: string;
@Prop()
phoneNumber: string
@Prop(raw({
jobSearchStatus: { type: String, enum: JOB_SEARCH_STATUS, required: true }
}))
jobPreferences: Record<string, any>;
@Prop(raw(externalLinks))
externalLinks: Record<string, any>;
@Prop([String])
skills: string[];
@Prop(raw({ type: address, required: false }))
address: Record<string, any>;
@Prop()
birthDate: Date;
@Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Employment' }] })
employments: Employment[];
@Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Education' }] })
educations: Education[];
@Prop(raw([language]))
languages: Record<string, any>[];
@Prop()
timeZone: string;
@Prop()
createdAt: Date;
@Prop()
updatedAt: Date;
@Prop({
enum: RECORD_STATUS,
required: true,
default: RECORD_STATUS.Active
})
recordStatus: string;
}
export const UserProfileSchema = SchemaFactory.createForClass(UserProfile);