问题
I have been trying to work through the NestJs example for the Serialization Section for Mongodb using Typegoose using the class-transformer library. The example given at https://docs.nestjs.com/techniques/serialization only shows how to use serialization in TypeORM. I followed the same process for Typegoose. Here is what I have tried so far.
// cat.domain.ts
import { prop } from '@typegoose/typegoose';
export class Cat {
@prop()
name: string;
@prop()
age: number;
@prop()
breed: string;
}
// cats.service.ts
@Injectable()
export class CatsService {
constructor(
@InjectModel(Cat) private readonly catModel: ReturnModelType<typeof Cat>,
) {}
findAll(): Observable<Cat[]> {
return from(this.catModel.find().exec());
}
findOne(id: string): Observable<Cat> {
return from(this.catModel.findById(id).exec());
}
...
}
// cat.response.ts
import { ObjectId } from 'mongodb';
import { Exclude, Transform } from 'class-transformer';
export class CatResponse {
@Transform(value => value.toString(), { toPlainOnly: true })
_id?: ObjectId;
name: string;
age: number;
@Exclude()
breed: string;
constructor(partial: Partial<CatResponse>) {
Object.assign(this, partial);
}
}
// cats.controller.ts
@Controller('cats')
@UseInterceptors(ClassSerializerInterceptor)
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Get()
findAll(): Observable<CatResponse[]> {
return this.catsService.findAll();
}
@Get(':id')
findOne(@Param() params: FindOneParamsDto): Observable<CatResponse> {
return this.catsService.findOne(params.id);
}
...
}
I tried running the API call on Get() with id but instead of the breed
being excluded from the response I have been getting the following response.
{
"$__": {
"strictMode": true,
"selected": {},
"getters": {},
"_id": {
"_bsontype": "ObjectID",
"id": {
"type": "Buffer",
"data": [
94,
93,
76,
66,
116,
204,
248,
112,
147,
216,
167,
205
]
}
},
"wasPopulated": false,
"activePaths": {
"paths": {
"_id": "init",
"name": "init",
"age": "init",
"breed": "init",
"__v": "init"
},
"states": {
"ignore": {},
"default": {},
"init": {
"_id": true,
"name": true,
"age": true,
"breed": true,
"__v": true
},
"modify": {},
"require": {}
},
"stateNames": [
"require",
"modify",
"init",
"default",
"ignore"
]
},
"pathsToScopes": {},
"cachedRequired": {},
"$setCalled": [],
"emitter": {
"_events": {},
"_eventsCount": 0,
"_maxListeners": 0
},
"$options": {
"skipId": true,
"isNew": false,
"willInit": true
}
},
"isNew": false,
"_doc": {
"_id": {
"_bsontype": "ObjectID",
"id": {
"type": "Buffer",
"data": [
94,
93,
76,
66,
116,
204,
248,
112,
147,
216,
167,
205
]
}
},
"name": "Sylver",
"age": 14,
"breed": "Persian Cat",
"__v": 0
},
"$locals": {},
"$op": null,
"$init": true
}
Can anyone help me with how to serialize response properly?
回答1:
this is an known issue (#108), typegoose (& mongoose) are incompatible with class-transformer/class-validator
this is because typegoose needs to translate the class into an schema and mongoose will compile it to an model (which isnt the class anymore)
回答2:
Here is a workaround:
// cats.controller.ts
...
import { classToPlain } from "class-transformer";
...
@Controller('cats')
@UseInterceptors(ClassSerializerInterceptor)
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Get()
findAll(): Observable<CatResponse[]> {
const cats = this.catsService.findAll();
// transforming the Model to CatResponse class...
const catResponses = cats.map(cat => classToPlain(new CatResponse(cat.toJSON())))
return catResponses;
}
@Get(':id')
findOne(@Param() params: FindOneParamsDto): Observable<CatResponse> {
const cat = this.catsService.findOne(params.id);
const catResponse = classToPlain(new CatResponse(cat.toJSON()));
return
}
...
}
Hope it could help.
来源:https://stackoverflow.com/questions/60525544/how-to-serialize-a-nest-js-response-with-class-transformer-while-getting-data-wi