Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

class-transformer not working properly #169

Open
necm1 opened this issue Apr 21, 2022 · 6 comments
Open

class-transformer not working properly #169

necm1 opened this issue Apr 21, 2022 · 6 comments
Labels
bug Something isn't working

Comments

@necm1
Copy link

necm1 commented Apr 21, 2022

Hey!

I'm actually facing an issue using class-transformer using NestJS. I try to exclude some properties for my response, but getting following error:

TypeError: obj.toObject is not a function

Method I'm using to create paginate:

    const posts = await this.post.paginate(undefined, {
      limit: 10,
      page,
      populate: [
        {
          path: 'user',
          transform: (doc: any, id: any) => {
            return new User(doc);
          },
          populate: {
            path: 'profile',
            model: 'Profile',
            transform: (doc: any, id: any) => {
              return new Profile(doc);
            },
          },
        },
        {path: 'book'},
      ],
      sort: {_id: -1},
    });

The following entities User & Profile is a normal Scheme which looks for example like this:

@Schema({collection: 'users', versionKey: false})
/**
 * @class User
 */
export class User {
  @Exclude()
  /**
   * @public
   * @property
   * @type {string}
   */
  public id: string;

  @Prop({required: true, unique: true})
  /**
   * @public
   * @property
   * @type {string}
   */
  public username: string;

  @Prop({required: true})
  @Exclude()
  /**
   * @public
   * @property
   * @type {string}
   */
  public password: string;

  @Prop({required: true, unique: true})
  /**
   * @public
   * @property
   * @type {string}
   */
  public email: string;

  @Exclude()
  @Prop()
  /**
   * @public
   * @property
   * @type {Date}
   */
  public created_at: Date;

  @Prop()
  @Exclude()
  /**
   * @public
   * @property
   * @type {Date}
   */
  public updated_at: Date;

  @Prop({type: Types.ObjectId, ref: 'Profile'})
  /**
   * @public
   * @property
   * @type {Profile}
   */
  public profile: Profile | Types.ObjectId;

  /**
   * User constructor
   *
   * @constructor
   * @param {Partial<User>} partial
   */
  constructor(partial: Partial<User>) {
    Object.assign(this, partial);
  }
}

How I create the response:

    const posts = await this.postService.getHomePostsPaginate(
      query.page ? query.page : 1
    );

    const postsArray: any[] = [];

    posts.docs.forEach((v) => {
      // @TODO transform v.user & v.user.profile
      v.user = new User(v);
      v.user.profile = new Profile(v.user.profile);
      postsArray.push(v);
    });

Even without using the transform object in my populate I'm facing the same error.

I've an example where it works using findOne() (Excluding properties works):

    const user = await this.userService.getByName(req.user.username, true);
    user.profile = new Profile(user.profile);
``

Is there any reason for this behaviour? I appreciate every help!
@aravindnc
Copy link
Owner

Duplicate of #160

@aravindnc aravindnc marked this as a duplicate of #160 Jun 8, 2022
@aravindnc
Copy link
Owner

@necm1 It seems there is an issue with toObject, which we need to figure it out.

@aravindnc aravindnc added the bug Something isn't working label Jun 8, 2022
@aravindnc
Copy link
Owner

I have spent sometime with this, and still no idea what's causing this issue.

@georgeben
Copy link

@necm1 Please how did you add paginate method to your mongoose model? Typescript keeps throwing an error that paginate does not exist on a mongoose document.

@necm1
Copy link
Author

necm1 commented Aug 26, 2022

@necm1 Please how did you add paginate method to your mongoose model? Typescript keeps throwing an error that paginate does not exist on a mongoose document.

You need to use the PaginateModel<T>-interface i.e.:

import {PaginateModel} from 'mongoose';

  /**
   * BookService constructor
   *
   * @constructor
   * @param {PaginateModel<Book & Document>} book
   * @param {CacheService} cacheService
   * @param {AuthorService} authorService
   */
  constructor(
    @InjectModel(Book.name) private book: PaginateModel<Book & Document>,
    private readonly cacheService: CacheService,
    private readonly authorService: AuthorService
  ) {}

@aravindnc some time passed - did you find any solution / fix for this issue?

@johnpozy
Copy link

johnpozy commented Aug 19, 2024

this solution is working for me. mongoose-paginate-v2 return docs object alongside with other data such as totalDocs, totalPages etc.. the docs is equivalent to my schema, so i just re-convert it to object using plainToClass from class-transformer and the @Exclude() annotation is working as expected.

@Schema({
  collection: 'services',
  timestamps: true,
  toJSON: {
    virtuals: true,
    transform: (doc, ret) => {
      ret['id'] = ret['_id'];

      if (ret['fee'] && ret['fee'].length > 0) {
        ret['fees'] = ret['fee'][0]['ref'];
      }
    },
  },
})
export class Service implements IService {
  @Prop({
    type: mongoose.Schema.Types.ObjectId
  })
  @Exclude()
  _id: string;

  @Prop({
    type: mongoose.Schema.Types.ObjectId
  })
  id: string;

  @Prop({ type: String })
  service: string;

  @Prop({
    type: String,
    enum: EServiceType,
  })
  type: EServiceType;

  @Prop({
    type: String,
    enum: EServiceType,
  })
  vehicleType: EServiceType;

  @Prop({
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Service',
  })
  @Type(() => Service)
  parent?: string | undefined;

  @Exclude()
  @Prop([
    {
      type: ServiceFee,
    },
  ])
  @Type(() => ServiceFee)
  fee: ServiceFee[];

  @Prop({
    type: mongoose.Schema.Types.ObjectId,
    ref: ServiceFeeComponent.name,
  })
  @Type(() => ServiceFeeComponent)
  fees: ServiceFeeComponent[];

  @Prop({
    type: Date,
  })
  createdAt: Date;

  @Prop({
    type: Date,
  })
  updatedAt: Date;

  @Prop({
    type: String,
  })
  created_by: string;

  @Prop({
    type: String,
  })
  updated_by: string;

  constructor(partial: Partial<Service>) {
    Object.assign(this, partial);
  }
}

export const ServiceSchema = SchemaFactory.createForClass(Service);

ServiceSchema.plugin(mongoosePaginate);
public getServices = async (query: FilterQuery<Service>, options: PaginateOptions) => {
  return this._serviceModel
    .paginate(query, options)
    .then((services: PaginateResult<Service>) => ({
      ...services,
      docs: plainToClass(Service, JSON.parse(JSON.stringify(services.docs)))
    }));
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants