Node+TS+Sequelize 数组map内OR运算符处理货币价格相加异常问题
错误根因
你的代码逻辑存在两个核心问题:
- 调用
Crypto.findAll查询时仅指定了req.query.currency对应字段和createdAt作为返回属性,因此allPrices中每个price对象仅存在当前请求的货币属性,另外两个未查询的货币属性会返回null或undefined,转为数字后为0或NaN。 - JS逻辑或
||运算符的执行规则是返回第一个真值,不管你当前请求的是哪种货币,都会先计算BTCUSD分支的结果,只要该结果的字符串不是空值(几乎所有场景下都满足),就会直接返回第一个分支的结果,永远不会触发后面ETHUSD、LTCUSD的计算逻辑,自然返回错误值。
修复方案
你已经通过req.query.currency拿到了当前请求的货币类型,直接用变量作为属性名取值即可,不需要写冗余的OR判断,同时建议先增加参数合法性校验,避免SQL注入风险,修改后代码如下:
const getHistorycalPrices = async (req: IGetHistorycalPricesRequest, res: IGetHistorycalPricesResponse) => { try { const allowedCurrencies = ['BTCUSD', 'ETHUSD', 'LTCUSD'] // 先校验参数合法性 if (!req.query.currency || !allowedCurrencies.includes(req.query.currency)) { res.status(400).send({ success: false, message: "Could not get historycal prices", }); return; } // Gets currency column by query from crypto DB table const allPrices = await Crypto.findAll({ attributes: [req.query.currency, 'createdAt'], order: [['createdAt', 'DESC']] }); if (!allPrices) { res.status(400).send({ success: false, message: "Could not get historycal prices", }); return; } // Get first row from crypto DB table const firstRowPrices = await Crypto.findByPk(1); if (!firstRowPrices) { res.status(400).send({ success: false, message: "Could not get first row prices", }); return; } // 直接用动态属性名取值,不需要OR判断 const currentCurrency = req.query.currency res.status(200).send({ success: true, message: "Successfully retrieved historycal prices", data: allPrices.map((price) => ({ cryptoPrices: (+price[currentCurrency] + +firstRowPrices[currentCurrency]).toString(), createdAt: price.createdAt.toDateString(), })), }); return; } catch (e) { res.status(500).send({ success: false, message: "Server error", }); return; } };
可选优化
如果需要避免字段空值导致计算结果异常,可以给取值逻辑增加兜底:
cryptoPrices: (+(price[currentCurrency] || 0) + +(firstRowPrices[currentCurrency] || 0)).toString()
内容的提问来源于stack exchange,提问作者user16657995
相关产品推荐
相关产品推荐

