我对包含type列的表进行了此简单查询bigint。
bigint
但是,当我查询它时,pg-promise将该列的值作为字符串返回。我在文档中找不到有关此信息。那是标准行为吗?
var ids = [180, 120]; db.any('SELECT id_brand, brand from catalog_brand WHERE id_brand in ($1:csv)', [ids]) .then((data) => { // return results });
data 采用以下形式,其中id作为字符串而不是int:
data
[{id_brand: "180", brand: "Ford"}, {id_brand: "120", brand: "Nike"}]
有什么指示pg-promise返回实际类型吗?
历史上一直在积淀很多东西。但是,如果您使用的是Node.js v10.4.0或更高版本,则可以跳过所有步骤,然后跳到UPDATE-2底部的部分。
UPDATE-2
这确实是标准行为。
bigint是64位,并且所有64位整数都由底层的node-postgres驱动程序作为type string返回,而32 位整数则作为返回number。
string
number
原因是64位整数在JavaScript中没有确切的本机表示形式,它只能以一定的精度显示64位数字,并且不适合表示64位数字的全部范围。
有三种可能的解决方案,请选择一种最适合您的解决方案:
解决方案1
不要使用64位整数来存储Id-s,如果您的表预计不会有超过40亿条记录,请改用默认int类型32位,它将自动以整数形式返回。
int
解决方案2
即时将返回的id转换为整数,但请记住,一旦id达到足够高的数字(53位),转换后的值就会失真/更改。
但是,您可以使用专用的库,该库可以将字符串正确地转换为64位整数(请参见上面的链接),但是在查询中使用时可能很麻烦。
即时转换id的示例:
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 });
参见Database.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 });
请参阅Database.one。
解决方案3
您可以使底层的node-postgres驱动程序忽略转换安全性,并将此类类型转换为无处不在的整数。我不能说这通常是否是一个好主意,只能通过pgp.pg.types.setTypeParser(...)(请参阅pg- types)轻松完成:
pgp.pg.types.setTypeParser(...)
// Convert bigserial + bigint (both with typeId = 20) to integer: pgp.pg.types.setTypeParser(20, parseInt);
更新1
当pg-promise通过TypeScript 使用v9或更高版本时,可以用以下代码替换上面的代码:
pg-promise
pgp.pg.types.setTypeParser(TypeId.INT8, parseInt);
请注意,解决方案2和3做相同的事情,但是在两个不同的级别上:
更新2
该库的9.3.0版添加了对本机BigInt类型的支持,如果您正在运行Node.js v10.4.0或更高版本,则现在可以使用该类型。
为了使驱动程序自动将BigInt用于BIGINT+ BIGSERIAL:
BIGINT
BIGSERIAL
pgp.pg.types.setTypeParser(20, BigInt); // Type Id 20 = BIGINT | BIGSERIAL
有关更多详细信息,请参见项目的WiKi中的BigInt手册。