2k1
  • Home
  • Programming
  • System
  • Design
  • Applications
  • Tech
No Result
View All Result
  • Login
2k1
  • Home
  • Programming
  • System
  • Design
  • Applications
  • Tech
No Result
View All Result
2k1
No Result
View All Result

Cheatsheet: ObjectId bị trả về random khi dùng plainToInstance

Nguyen Pham by Nguyen Pham
19/08/2026
in Blog
Reading Time: 5 mins read
A A
0

Triệu chứng

Field kiểu ObjectId trong response DTO trả về giá trị khác nhau mỗi lần gọi API, dù data gốc trong DB không đổi. Log cho thấy giá trị trong @Transform là các ObjectId mới, timestamp gần nhau (tạo liên tiếp trong cùng 1 tick).

detail.internalInvoiceId  → “6a7a88a78b6a1bd07124a726”   (ổn định, đọc trực tiếp)

value trong @Transform    → ObjectId(“6a852ae4e990404b4b96f49f”)  (khác mỗi lần!)

Root cause

Field có @Transform nhưng không có @Type() đi kèm.

class-transformer không biết target type, và khi gặp value là instance có constructor riêng (như Types.ObjectId), nó cố “clone” bằng cách gọi new value.constructor() không có argument rồi copy properties sang. Nhưng:

new Types.ObjectId()  // không có argument → tự sinh ObjectId RANDOM MỚI

→ Kết quả: @Transform nhận một ObjectId hoàn toàn mới, không phải giá trị gốc.

Điều kiện để bug xảy ra

  • ✅ Field nhận trực tiếp ObjectId (hoặc Date, Buffer — các class có constructor side-effect tương tự)
  • ✅ Có @Transform, không có @Type()
  • ✅ plainToInstance không bật enableImplicitConversion: true

Cách fix — chọn 1 trong 3

Fix 1: Bật enableImplicitConversion (fix nhanh, toàn cục)

plainToInstance(Dto, detail, {

  excludeExtraneousValues: true,

  enableImplicitConversion: true, // bỏ qua nhánh “clone qua constructor”

});

⚠️ Fix ở tầng call site — chỉ nên dùng làm safety net, không thay thế fix tận field.

Fix 2: Thêm @Type(() => String) (đơn giản nhất, khuyến nghị)

@ApiProperty()

@Expose()

@Type(() => String)

internalInvoiceId: string;

String(objectId) tự động gọi đúng .toHexString() nhờ custom toString() của ObjectId — không cần @Transform nữa. Target type rõ ràng nên class-transformer không cần đoán/clone.

Fix 3: Custom decorator dùng chung (khuyến nghị nếu nhiều DTO bị)

// decorators/expose-object-id.decorator.ts

import { Expose, Transform } from ‘class-transformer’;

import { Types } from ‘mongoose’;

import { applyDecorators } from ‘@nestjs/common’;

export function ExposeObjectId() {

  return applyDecorators(

    Expose(),

    Transform(({ value }) => {

      if (!value) return null;

      return value instanceof Types.ObjectId

        ? value.toHexString()

        : String(value);

    }),

  );

}

@ApiProperty()

@ExposeObjectId()

internalInvoiceId: string;

Field tự chủ động convert đúng, không phụ thuộc vào enableImplicitConversion ở call site.

Quy tắc chung để tránh lặp lại

Tình huốngViệc cần làm
Field nhận ObjectId/Date/Buffer từ Mongoose, có @TransformLuôn thêm @Type() tương ứng, hoặc dùng decorator gộp sẵn
Không chắc control hết mọi fieldSet enableImplicitConversion: true làm safety net
Muốn tránh toàn bộ vấn đề class-instance quirks.lean() ngay từ query Mongoose, hoặc JSON.parse(JSON.stringify(doc)) trước khi plainToInstance
Nhiều DTO cùng patternGrep toàn project field xxxId: string map từ ObjectId → áp @ExposeObjectId() đồng loạt

Debug nhanh khi nghi ngờ bug tương tự

console.log(‘is Document?’, detail instanceof Document);

console.log(‘typeof field’, typeof detail.someField, detail.someField?.constructor?.name);

console.log(‘raw’, detail.toObject ? detail.toObject().someField : detail.someField);

Nếu constructor.name là ObjectId/Date/… và field không có @Type() → nghi ngờ ngay bug này.

Previous Post

Monitor container project

Related Posts

Blog

Monitor container project

by Nguyen Pham
10/03/2026
Blog

Sức mạnh của AI Agent trong năm 2026: Kỷ nguyên tự động hóa thông minh

by Nguyen Pham
01/02/2026
Blog

Khám phá OpenClaw: Trợ lý AI Cá nhân Đa nền tảng và Quyền năng

by Nguyen Pham
31/01/2026
Blog

Cảnh báo khẩn: Thu hồi sữa Aptamil (Đức và Anh) do nghi nhiễm độc tố nguy hiểm (2026)

by Nguyen Pham
31/01/2026
Lập trình Rust Cơ Bản: Khám Phá Struct – Sức Mạnh Của Kiểu Dữ Liệu Tùy Chỉnh
Blog

Lập trình Rust Cơ Bản: Khám Phá Struct – Sức Mạnh Của Kiểu Dữ Liệu Tùy Chỉnh

by Nguyen Pham
01/01/2026
Chứng Khoán và Tài Chính: Chìa Khóa Mở Cánh Cửa Thịnh Vượng Cá Nhân và Doanh Nghiệp
Blog

Chứng Khoán và Tài Chính: Chìa Khóa Mở Cánh Cửa Thịnh Vượng Cá Nhân và Doanh Nghiệp

by Nguyen Pham
17/11/2025
Load More
Please login to join discussion

@2021 2k1.org [email protected]

No Result
View All Result
  • Home
  • Review
  • Applications
  • Computers
  • Gaming
  • Microsoft

© 2021 NData

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In