class-transformer
class-transformer copied to clipboard
fix: _id changes when {_id: new ObjectId(id) } is passed
Description
ObjectId from 'mongodb' driver Whenever { _id: new ObjectId(id) } is passed to plainToInstance function it return an object with different _id as if _id is a new call of new ObjectId() with no arguments. Happens when replacing full objects on mongoDB
const { id } = req?.params;
const _id = new ObjectId(id);
const updatedTile = plainToInstance(Tile, { ...(req.body as Tile), _id });
As of Tile is a class to be transformed to
Expected behavior
Return object with same _id
Actual behavior
Return object with different _id - _id equals to new call of new ObjectId()
This is my first time to post an issue so there might be details missing, Please tell me if so and I'll make sure to edit
Same here... @liel-almog did you recently update your mongodb driver from 3.x to 4.x? It still seems to work for me with mongodb driver 3.x. As soon as I update my driver, class-transformer does exactly what you described.
My current workaround is to reset the id after I called plainToInstance!
Hello there, @maxfriedmann
I created an _id on the frontend and when I send the model ( object ) to the backend the _id field has be resetted when using plainToInstance. I think the problem ObjectId is not parsable / serializable. I looked back in older issues and found an answer, the @ExsposeId decorator that blinds with TS. This is a good answer #484 with a little adjustment need to be made with a newer types . I could send the new decorator if you'd like
Great, yes please! Or share it here so others that run into the same problem can benefit as well!
As of my version "class-transformer": "^0.5.1" To make ExposeId work in TypeScript, this is the currect version of ExposeId extended from #484. I may recommend make the name more generic as it may be able to work with any non serializable initiated class This is a good decorator because it helps make a property on class required and not optional
import { ExposeOptions, Transform, TransformFnParams } from "class-transformer";
export const ExposeId = (options?: ExposeOptions) =>
// tslint:disable-next-line: ban-types
((target: Object, propertyKey: string) => {
Transform((params: TransformFnParams) => params.obj[propertyKey])(target, propertyKey);
});
Great, yes please! Or share it here so others that run into the same problem can benefit as well!
Please let me know if it works 😀
@liel-almog You save my day ! thanks a lot.
Great solution @liel-almog !. Works for me. Thank you!
@liel-almog solution with Expose and name
property from ExposeOptions.
import { Expose, TransformFnParams, Transform, ExposeOptions } from "class-transformer";
export const ExposeId = (options?: ExposeOptions): PropertyDecorator =>
(target: Object, propertyKey: string | symbol) => {
Transform((params: TransformFnParams) => params.obj[options?.name ? options.name : propertyKey])(target, propertyKey);
Expose(options)(target, propertyKey);
};
Example:
@ExposeId({ name: "_id"})
id: string;
@ExposeId()
userId: string;