Node.js Sequelize中DOUBLE(10,2)返回整数问题求解
问题:Sequelize中DOUBLE/DECIMAL类型字段补零格式化输出
在Node.js的Sequelize框架中,使用DataTypes.DOUBLE(10,2)或DataTypes.DECIMAL(10,2)定义字段时,会出现这样的情况:当字段值小数部分为0时返回整数(如2400),仅小数部分非0时才返回带小数的数值(如2400.5)。需求是让base_fare字段无论是否有小数部分,都输出2400.00这类保留两位小数的格式。
提供的迁移文件代码
'use strict'; module.exports = { async up(queryInterface, Sequelize) { await queryInterface.createTable('properties', { id: { allowNull: false, autoIncrement: true, primaryKey: true, type: Sequelize.INTEGER }, serial: { type: Sequelize.INTEGER, allowNull: false, }, name: { type: Sequelize.STRING, }, type: { type: Sequelize.STRING, allowNull: false, }, base_fare: { type: Sequelize.DOUBLE(10,2) }, current_fare : { type: Sequelize.DOUBLE(10,2) }, tenant_id: { type: Sequelize.INTEGER, }, booking_id : { type: Sequelize.INTEGER }, building_id : { type: Sequelize.INTEGER, allowNull: false, onDelete: 'CASCADE', } }); }, async down(queryInterface, Sequelize) { await queryInterface.dropTable('properties'); } };
提供的模型文件代码
'use strict'; const { Model } = require('sequelize'); module.exports = (sequelize, DataTypes) => { class Property extends Model { static associate(models) { // Removed for readability } } Property.init({ serial: DataTypes.INTEGER, type: DataTypes.STRING, name: DataTypes.STRING, base_fare: DataTypes.DOUBLE(10,2), current_fare: DataTypes.DOUBLE(10,2), tenant_id: DataTypes.INTEGER, booking_id: DataTypes.INTEGER, building_id: DataTypes.INTEGER, }, { sequelize, modelName: 'Property', timestamps: false, omitNull: false, name: { singular: 'property', plural: 'properties' }, underscored: true }); return Property; };
示例数据
{ "id": 11, "serial": 19, "type": "", "name": "Room", "base_fare": 2400, "current_fare": null, "tenant_id": null, "booking_id": null, "building_id": 1 }, { "id": 12, "serial": 19, "type": "", "name": "Room", "base_fare": 2400.5, "current_fare": null, "tenant_id": null, "booking_id": null, "building_id": 1 }
解决方案
方法一:给字段添加getter函数格式化输出
直接在模型的字段定义中添加getter逻辑,对返回值进行格式化:
Property.init({ // ...其他字段 base_fare: { type: DataTypes.DOUBLE(10,2), get() { const value = this.getDataValue('base_fare'); // 若值存在则保留两位小数,否则返回null return value ? value.toFixed(2) : null; } }, current_fare: { type: DataTypes.DOUBLE(10,2), get() { const value = this.getDataValue('current_fare'); return value ? value.toFixed(2) : null; } }, // ...其他字段 }, { // ...模型配置 });
注意:toFixed(2)会将数值转为字符串,如果需要保持数值类型,可改用parseFloat(value.toFixed(2)),但这样2400.00会变回2400,若必须显示两位小数,建议保留字符串类型或在前端做处理。
方法二:新增虚拟字段专门返回格式化值
如果不想修改原字段的返回格式,可以添加虚拟字段来输出格式化后的结果:
Property.init({ // ...原有字段 formatted_base_fare: { type: DataTypes.VIRTUAL, get() { const value = this.getDataValue('base_fare'); return value ? value.toFixed(2) : null; } }, // ...其他字段 }, { // ...模型配置 });
查询时直接获取formatted_base_fare字段即可得到格式化后的结果。
方法三:查询时用SQL函数格式化
在数据库层面直接处理格式化,不同数据库对应函数不同:
- MySQL使用
FORMAT函数:
const properties = await Property.findAll({ attributes: [ 'id', 'serial', 'type', 'name', [sequelize.fn('FORMAT', sequelize.col('base_fare'), 2), 'base_fare'], 'current_fare', 'tenant_id', 'booking_id', 'building_id' ] });
- PostgreSQL使用
TO_CHAR函数:
const properties = await Property.findAll({ attributes: [ 'id', 'serial', 'type', 'name', [sequelize.fn('TO_CHAR', sequelize.col('base_fare'), '99999999.99'), 'base_fare'], 'current_fare', 'tenant_id', 'booking_id', 'building_id' ] });
额外建议:优先用DECIMAL处理金额
金额类字段建议使用DataTypes.DECIMAL(10,2)替代DOUBLE,因为DOUBLE是浮点数存在精度丢失风险,DECIMAL是精确小数类型更适合金额场景。只需修改迁移文件和模型中的字段类型即可:
迁移文件:
base_fare: { type: Sequelize.DECIMAL(10,2) }, current_fare : { type: Sequelize.DECIMAL(10,2) }
模型文件:
base_fare: DataTypes.DECIMAL(10,2), current_fare: DataTypes.DECIMAL(10,2),
内容的提问来源于stack exchange,提问作者Rafat Rashid Rahi
相关产品推荐
相关产品推荐

