下面有很多历史积累的内容。但如果您使用 Node.js v10.4.0 或更高版本,您可以跳过所有这些,并跳到部分UPDATE-2
在底部。
这确实是标准行为。
bigint
是64位的,所有64位整数都是底层返回的节点 postgres驱动程序作为类型string
,而 32 位则返回为number
.
原因是64位整数在JavaScript中没有精确的原生表示,它只能以一定的精度表示64位数字,并且不适合表示全范围的64位数字。
也可以看看:如何在 Node.js 中进行 64 位整数运算?
此问题有三种可能的解决方案,选择最适合您的一种:
解决方案1
不要使用 64 位整数来存储 Id-s,如果您的表预计不会有超过 40 亿条记录,请使用默认值int
type 而是 32 位,并且会自动以整数形式返回。
解决方案2
将返回的 id-s 即时转换为整数,但请记住,一旦您的 id-s 达到足够高的数字(53 位),转换后的值将被扭曲/更改。
不过,您可以使用专门的库来正确地将字符串转换为 64 位整数(请参阅上面的链接),但这在跨查询中使用可能会很尴尬。
即时转换 id-s 的示例:
db.each('SELECT id_brand FROM catalog_brand WHERE id_brand in ($1:csv)', [ids], cat=> {
cat.id_brand = parseInt(cat.id_brand)
})
.then(rows => {
// id_brand is now an integer in each row
});
See 数据库.each.
作为另一个示例,记录计数始终返回为bigint
,因此获得这些的最佳方法是通过内联值转换+转换,如下所示:
db.one('SELECT count(*) FROM catalog_brand', [], c => +c.count)
.then(count => {
// count = a proper integer value, rather than an object with a string
});
See 数据库.一.
解决方案3
你可以做底层节点 postgres驱动程序忽略转换安全性并将此类类型到处转换为整数。我不能说这总体上是否是一个好主意,只是可以通过以下方式轻松完成pgp.pg.types.setTypeParser(...)
(see pg-types):
// Convert bigserial + bigint (both with typeId = 20) to integer:
pgp.pg.types.setTypeParser(20, parseInt);
UPDATE-1
使用时pg-promise
v9 或更高版本通过 TypeScript,您可以将上面的代码替换为:
pgp.pg.types.setTypeParser(TypeId.INT8, parseInt);
请注意,解决方案 2 和 3 执行相同的操作,但在两个不同的级别上:
- 解决方案 2 中的显式本地转换
- 解决方案 3 中的隐式全局转换
UPDATE-2
版本9.3.0该库添加了对本机的支持BigInttype,如果您运行的是 Node.js v10.4.0 或更高版本,现在您可以使用它。
让驱动程序自动使用BigInt for BIGINT
+ BIGSERIAL
:
pgp.pg.types.setTypeParser(20, BigInt); // Type Id 20 = BIGINT | BIGSERIAL
有关更多详细信息,请参阅BigInt手册在该项目的 WiKi 中。