Class-transformer: databaseToClass

Created on 22 Mar 2018  路  8Comments  路  Source: typestack/class-transformer

Hello,

I was attempting to use this library to map DB values to a class (plainToClass). However, it's not supporting other objects such as a BSON ObjectID. I think it doesn't support ObjectID because of this line here:

https://github.com/mongodb/js-bson/blob/1.0-branch/lib/bson/objectid.js#L55

So I have two questions regarding this.

I have this Mongo doc:

{
  _id: ObjectId('...'),
  foo: 'bar',
  createdAt: Date
}

and class:

class Example {
  id: ObjectId;
  foo: string;
  createdAt: Date;
}
  1. Can I map an ObjectID value?
  2. Can my input JSON's field be converted to another field name? (_id to id)

Thanks!

transformations question

Most helpful comment

If you are using NestJs with mongoose, you can simply do:

Schema File

export const ExampleSchema = new Schema({
  foo: String,
  createdAt: Date
});

Interface

export interface Example extends Document {
  id: string; // NOTE: This field will be automatically mapped by the framework
  foo: string;
  createdAt: Date;
}

Dto Class

export class ExampleDto {
  @Expose()
  id: string;

  @Expose()
  foo: string;

  @Expose()
  createdAt: Date;
}

Controller

import { plainToClass } from 'class-transformer';
...
@Get()
async getExample() {
    const result = await this.service.getExample();
    return plainToClass(
      ExampleDto, result, { strategy: 'excludeAll', enableImplicitConversion: true } // enableImplicitConversion is the magic, otherwise mongodb Id will be incorrectly converted 
    );
}

Enjoy guys

All 8 comments

Have you seen TypeORM? It's exactly what you are looking for.

Ooops, I thought I replied to this. I have seen TypeORM. We're using MongoDB at the moment, and their current implementation of MongoDB is using an old driver and their issues keep growing on the Mongo side. Plus in most of our situations, we don't need a heavy object mapper like TypeORM. Mongo has a built-in "map" function on their cursor.

class User {
  id: ObjectId;
  username: string;
  pass: string;
}

const users = await userCollection
  .find()
  .map((doc) => plainToClass(User, doc))
  .toArray();

I was planning on the repository layer doing mapping for any class and using class-transformer to aid in it.

One issue I ran into is that the mapper, when running into ObjectId, internally tries to create a Buffer and errors out. (my 1. issue above)

I guess this is because we call this object with an invalid constructor.

We don't support to overgive a value (because no info is given at runtime about what information is needed). So the id is set to undefined, which is not checked by them a exception is thrown.

I think is the same as this #174.

Maybe you could work around this by using the @Transform-decorator

@j If you don't need this anymore, please close this issue.

@MTschannett is right you can work around your issue via using the @Transform and the @Expose operator.

class Example {
  @Expose({ name: '_id' })
  @Transform((objectId) => objectId.str, { toClassOnly: false })
  id: string;
  foo: string;
  createdAt: Date;
}

A complete dummy example:

import { Expose, Transform, classToPlain, plainToClass } from 'class-transformer';

class Example {
  @Expose({ name: '_id' })
  @Transform((objectId) => objectId.str, { toClassOnly: false })
  id: string;
  foo: string;
  createdAt: Date;
}

const classInstance = plainToClass(Example, {
  _id: { x: 5, str: 'xxxxx' },
  foo: 'yyyyy',
  createdAt: new Date(),
});

console.log(classInstance); // Example聽{id: "xxxxx", foo: "yyyyy", createdAt: ...}
console.log(classInstance instanceof Example); // true

I will go ahead and close this, if you have any question please continue the discussion

If you are using NestJs with mongoose, you can simply do:

Schema File

export const ExampleSchema = new Schema({
  foo: String,
  createdAt: Date
});

Interface

export interface Example extends Document {
  id: string; // NOTE: This field will be automatically mapped by the framework
  foo: string;
  createdAt: Date;
}

Dto Class

export class ExampleDto {
  @Expose()
  id: string;

  @Expose()
  foo: string;

  @Expose()
  createdAt: Date;
}

Controller

import { plainToClass } from 'class-transformer';
...
@Get()
async getExample() {
    const result = await this.service.getExample();
    return plainToClass(
      ExampleDto, result, { strategy: 'excludeAll', enableImplicitConversion: true } // enableImplicitConversion is the magic, otherwise mongodb Id will be incorrectly converted 
    );
}

Enjoy guys

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings