class-transformer icon indicating copy to clipboard operation
class-transformer copied to clipboard

fix: _id changes when {_id: new ObjectId(id) } is passed

Open liel-almog opened this issue 3 years ago • 9 comments

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()

liel-almog avatar Dec 29 '21 19:12 liel-almog

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

liel-almog avatar Dec 29 '21 19:12 liel-almog

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!

maxfriedmann avatar Jan 12 '22 07:01 maxfriedmann

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

liel-almog avatar Jan 12 '22 08:01 liel-almog

Great, yes please! Or share it here so others that run into the same problem can benefit as well!

maxfriedmann avatar Jan 12 '22 08:01 maxfriedmann

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);
  });

liel-almog avatar Jan 12 '22 08:01 liel-almog

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 avatar Jan 12 '22 08:01 liel-almog

@liel-almog You save my day ! thanks a lot.

clement-m-kreactive avatar Mar 25 '22 12:03 clement-m-kreactive

Great solution @liel-almog !. Works for me. Thank you!

wgerez avatar Nov 04 '22 23:11 wgerez

@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;

RadekKpc avatar Jul 13 '23 09:07 RadekKpc