내 앱을 express.js에서 Nest.js로 옮기고 있는데 mongoose.Schema ({...})로 Schema를 선언하는 오래된 방법을 사용하지 않고 다른 mongoose Schema를 참조하는 방법을 찾을 수 없습니다.
문서의 예제를 사용하여 문제를 명확히 할 수 있습니다.
@Schema()
export class Cat extends Document {
@Prop()
name: string;
}
export const CatSchema = SchemaFactory.createForClass(Cat);
이제 내가 원하는 것은 다음과 같습니다.
@Schema()
export class Owner extends Document {
@Prop({type: [Cat], required: true})
cats: Cat[];
}
export const OwnerSchema = SchemaFactory.createForClass(Owner);
이런 방식으로 스키마를 정의하면 다음과 같은 오류가 발생합니다. 잘못된 스키마 구성 : Cat
배열 내에서 유효한 유형이 아닙니다.cats
그렇다면 스키마를 정의하는 데 더 많은 OO 접근 방식을 사용하여 한 스키마를 다른 스키마 내부에서 참조하는 적절한 방법은 무엇입니까?
나는 소스 코드를 파헤쳐 서 Schema 클래스가 SchemaFactory.createForClass
메소드에 의해 어떻게 변환되는지 배웠다 .
@Schema()
export class Cat extends Document {
@Prop()
name: string;
}
export const catSchema = SchemaFactory.createForClass(Cat);
기본적으로 할 때 SchemaFactory.createForClass(Cat)
Nest는 클래스 구문을 Mongoose 스키마 구문으로 변환하므로 결국 변환 결과는 다음과 같습니다.
const schema = new mongoose.Schema({
name: { type: String } // Notice that `String` is now uppercase.
});
이 파일을보세요 : mongoose / prop.decorator.ts at master · nestjs / mongoose · GitHub
export function Prop(options?: PropOptions): PropertyDecorator {
return (target: object, propertyKey: string | symbol) => {
options = (options || {}) as mongoose.SchemaTypeOpts<unknown>;
const isRawDefinition = options[RAW_OBJECT_DEFINITION];
if (!options.type && !Array.isArray(options) && !isRawDefinition) {
const type = Reflect.getMetadata(TYPE_METADATA_KEY, target, propertyKey);
if (type === Array) {
options.type = [];
} else if (type && type !== Object) {
options.type = type;
}
}
TypeMetadataStorage.addPropertyMetadata({
target: target.constructor,
propertyKey: propertyKey as string,
options,
});
};
}
여기서 Prop()
데코레이터가 씬 뒤에서하는 일을 볼 수 있습니다 . 당신이 할 때 :
@Prop()
name: string;
Prop
이 경우 인수없이 함수가 호출됩니다.
const type = Reflect.getMetadata(TYPE_METADATA_KEY, target, propertyKey);
Reflect
API를 사용하면 .NET을 실행할 때 사용하는 데이터 유형을 가져올 수 있습니다 name: string
. type
이제 변수 값 이로 설정됩니다 String
. 그렇지 않은 string
경우 Reflect
API는 항상 데이터 유형의 생성자 버전을 반환하므로 다음과 같습니다.
number
다음과 같이 직렬화됩니다. Number
string
다음과 같이 직렬화됩니다. String
boolean
다음과 같이 직렬화됩니다. Boolean
TypeMetadataStorage.addPropertyMetadata
그런 다음 아래의 개체를 저장소에 저장합니다.
{
target: User,
propertyKey: ‘name’,
options: { type: String }
}
다음을 살펴 보겠습니다 : mongoose / type-metadata.storage.ts at master · nestjs / mongoose · GitHub
export class TypeMetadataStorageHost {
private schemas = new Array<SchemaMetadata>();
private properties = new Array<PropertyMetadata>();
addPropertyMetadata(metadata: PropertyMetadata) {
this.properties.push(metadata);
}
}
그래서 기본적으로 그 개체가에 저장됩니다 properties
의 변수 TypeMetadataStorageHost
. TypeMetadataStorageHost
이러한 객체를 많이 저장할 싱글 톤입니다.
SchemaFactory.createForClass(Cat)
Mongoose 스키마를 생성하는 방법을 이해하려면 다음을 참조하십시오. mongoose / schema.factory.ts at master · nestjs / mongoose · GitHub
export class SchemaFactory {
static createForClass(target: Type<unknown>) {
const schemaDefinition = DefinitionsFactory.createForClass(target);
const schemaMetadata = TypeMetadataStorage.getSchemaMetadataByTarget(
target,
);
return new mongoose.Schema(
schemaDefinition,
schemaMetadata && schemaMetadata.options,
);
}
}
가장 중요한 부분은 : const schemaDefinition = DefinitionsFactory.createForClass(target);
. 여기에서 대상은 Cat
클래스입니다.
여기에서 메소드 정의를 볼 수 있습니다 : mongoose / definitions.factory.ts at master · nestjs / mongoose · GitHub
export class DefinitionsFactory {
static createForClass(target: Type<unknown>): mongoose.SchemaDefinition {
let schemaDefinition: mongoose.SchemaDefinition = {};
schemaMetadata.properties?.forEach((item) => {
const options = this.inspectTypeDefinition(item.options as any);
schemaDefinition = {
[item.propertyKey]: options as any,
…schemaDefinition,
};
});
return schemaDefinition;
}
schemaMetadata.properties
저장했을 때 저장 한 객체를 포함합니다 TypeMetadataStorage.addPropertyMetadata
.
[
{
target: User,
propertyKey: ‘name’,
options: { type: String }
}
]
다음 forEach
을 생성합니다.
{
name: { type: String }
}
결국 master · nestjs / mongoose · GitHub에서mongoose.Schema
생성자 mongoose / schema.factory.ts에 대한 인수로 사용됩니다 .
return new mongoose.Schema(
schemaDefinition,
schemaMetadata && schemaMetadata.options,
);
Prop()
논쟁 으로 무엇을 넣어야 합니까?
Nest가 forEach
Mongoose 스키마를 생성하는 시기를 기억 하십니까?
schemaMetadata.properties?.forEach((item) => {
const options = this.inspectTypeDefinition(item.options as any);
schemaDefinition = {
[item.propertyKey]: options as any,
…schemaDefinition,
};
});
options
그것을 얻으려면 inspectTypeDefinition
방법 을 사용하십시오 . 아래 정의를 볼 수 있습니다.
private static inspectTypeDefinition(options: mongoose.SchemaTypeOpts<unknown> | Function): PropOptions {
if (typeof options === 'function') {
if (this.isPrimitive(options)) {
return options;
} else if (this.isMongooseSchemaType(options)) {
return options;
}
return this.createForClass(options as Type<unknown>);
} else if (typeof options.type === 'function') {
options.type = this.inspectTypeDefinition(options.type);
return options;
} else if (Array.isArray(options)) {
return options.length > 0
? [this.inspectTypeDefinition(options[0])]
: options;
}
return options;
}
options
A는 function
같은 String
또는 SchemaType
직접적 반환하고, 몽구스 옵션으로 사용됩니다.options
인 Array
, 그 배열의 첫번째 인덱스를 반환하고 배열을 마무리한다.options
가 아닌 Array
나 function
, 그것은 일반 단지의 경우 예를 들어, object
같은 { type: String, required: true }
, 그것은 직접적으로 반환되고 몽구스 옵션으로 사용.에서 참조 추가 할 수 있도록 Cat
하는 방법에 대해 Owner
, 당신은 할 수 있습니다 :
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document, Schema as MongooseSchema } from 'mongoose';
import { Owner } from './owner.schema.ts';
@Schema()
export class Cat extends Document {
@Prop()
name: string;
@Prop({ type: MongooseSchema.Types.ObjectId, ref: Owner.name })
owner: Owner;
}
export const catSchema = SchemaFactory.createForClass(Cat);
에서 참조 추가하는 방법에 관해서는 Owner
에를 Cat
, 우리는 할 수있다 :
@Prop([{ type: MongooseSchema.Types.ObjectId, ref: Cat.name }])
댓글 섹션의 질문에 대한 답변 :
답을 제대로 읽었다면이를 수행 할 수있는 충분한 지식이 있어야합니다. 하지만 그렇지 않은 경우 여기에 TLDR 답변이 있습니다.
여기에 가기 전에 전체 답변을 읽어 보는 것이 좋습니다.
image-variant.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
@Schema()
export class ImageVariant {
@Prop()
url: string;
@Prop()
width: number;
@Prop()
height: number;
@Prop()
size: number;
}
export const imageVariantSchema = SchemaFactory.createForClass(ImageVariant);
image.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
import { imageVariantSchema, ImageVariant } from './imagevariant.schema';
@Schema()
export class Image extends Document {
@Prop({ type: imageVariantSchema })
large: ImageVariant;
@Prop({ type: imageVariantSchema })
medium: ImageVariant;
@Prop({ type: imageVariantSchema })
small: ImageVariant;
}
export const imageSchema = SchemaFactory.createForClass(Image);
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다