升级Mongoose至6.0.0后触发BSONTypeError: Decimal128参数错误
解决Mongoose 6升级后Decimal128转换的BSONTypeError问题
错误原因
Mongoose 6.x对BSON Decimal128类型的序列化/反序列化逻辑做了调整:
- 5.x版本中,mongoose返回的文档默认会把Decimal128字段自动序列化为字符串;
- 6.x版本则保留了Decimal128实例,而你的
TransformDecimal128装饰器未适配这种变化,导致plainToClass处理时,要么装饰器错误地尝试用Decimal128实例创建新的Decimal128对象,要么class-transformer默认逻辑无法识别该实例,触发构造参数校验错误。
解决方案
1. 修复TransformDecimal128装饰器逻辑
确保装饰器能正确识别并转换mongoose 6的Decimal128实例,同时区分转换方向(数据库→DTO 或 DTO→数据库):
import { Transform } from 'class-transformer'; import { Decimal128 } from 'mongoose'; export function TransformDecimal128() { return Transform(({ value }) => { // 从数据库取出的Decimal128实例,转换为number(或字符串,避免精度丢失) if (value instanceof Decimal128) { // 若数值过大建议用toString()保留精度,转number可能丢失小数位 return Number(value.toString()); } // 从DTO传入的数值,转换为Decimal128用于存储 if (typeof value === 'number' || typeof value === 'string') { return Decimal128.fromString(value.toString()); } return value; }); }
2. 调整mongoose文档的序列化方式
在获取inputObject时,先将mongoose文档转换为普通JS对象,把Decimal128实例转为字符串,减少装饰器的处理压力:
// 假设receiptDoc是mongoose查询返回的文档对象 const inputObject = receiptDoc.toObject({ getters: true, // 启用getters转换 virtuals: false, transform: (doc, ret) => { // 手动处理Decimal128字段转字符串 if (ret.sum instanceof Decimal128) { ret.sum = ret.sum.toString(); } return ret; } }); const result = plainToClass(GetReceiptDto, inputObject);
3. 确保class-transformer配置正确
调用plainToClass时启用隐式转换,确保装饰器逻辑被正确执行:
const result = plainToClass(GetReceiptDto, inputObject, { enableImplicitConversion: true, excludeExtraneousValues: true // 过滤DTO中未定义的字段 });
验证点
- 检查
GetReceiptDto中sum字段的类型是否为number(或string,若需保留高精度); - 测试从数据库查询数据后转换为DTO的流程,确认
sum字段正常转换且无报错; - 测试前端传入数值后转换为Decimal128存入数据库的流程,确保数据一致性。
内容的提问来源于stack exchange,提问作者Sophie Jacquin
相关产品推荐
相关产品推荐

