DEBUG.WIKI
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
OnlineSIM:在线接收短信,虚拟号码租用
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →

node:sqlite 查询报 Value is too large:让 INTEGER 按 BigInt 读取

node:sqlite 默认把 INTEGER 读取为 number,超过安全整数范围会拒绝返回。通过语句级 BigInt 读取保留数值,并处理 JSON 和下游类型边界。

db.prepare(sql).all() 查询失败,报 RangeError: Value is too large to be represented as a JavaScript number,并带 ERR_OUT_OF_RANGE。如果报出的值大于 JavaScript 安全整数上限,先调整读取类型,不要急着修改 SQLite 字段或把大整数四舍五入。

这种情况在 Node.js 26.2.0、Windows x64读取浏览器历史数据库时有完整故障记录。它符合 node:sqlite 的类型转换规则:SQLite INTEGER 可保存的整数范围大于 JavaScript number 的安全整数范围,默认读取不能无损表示时会拒绝返回。

错误可能来自 SELECT * 中没注意到的列

JavaScript 的 Number.MAX_SAFE_INTEGER 是9007199254740991。数据库中的时间戳、标识符或内部整数超过它时,即使业务只关心另一列,SELECT * 也会触发转换失败。

先确认实际执行的查询及返回列。如果只需要地址和标题,可明确选择需要的列,避免把无关的大整数也拉进结果。但业务确实需要的标识符或时间字段,不能通过不读它来假装数据已正确处理。

不要先写成 CAST(id AS REAL) 或读取后调用 Number()。一旦转换过程损失精度,再转字符串也无法找回原值。错误中的数值只是线索,还需要按字段含义决定结果在应用中使用 bigint 还是字符串。

为这条语句打开大整数读取

下面示例按 Node.js 24.22.0 的 DatabaseSync、StatementSync 接口编写,读取已有数据库,不修改其内容。app.db、表名与列名均需替换为实际值:

const { DatabaseSync } = require('node:sqlite');

const db = new DatabaseSync('app.db', { readOnly: true });
try {
  const statement = db.prepare('SELECT id, title FROM items');
  statement.setReadBigInts(true);
  const rows = statement.all();

  for (const row of rows) {
    console.log(row.id.toString(), row.title);
  }
} finally {
  db.close();
}

setReadBigInts(true) 要在执行查询之前调用,作用于该语句读取的 INTEGER 字段,不会重写数据库,也不改变写入规则。它按整数类型转换,因此结果中的小整数同样可能变成 bigint;不要只在大值出现时才让调用方临时猜类型。

不同Node分支的构造器名称和连接选项有演进。示例刻意使用已核对的24.22.0接口;26.2.0也使用 DatabaseSync。若项目使用其他版本,先按实际安装版本核对,不能把最新文档中的新构造器或连接参数直接复制到旧环境。

BigInt 读出来后,还要检查传输边界

默认 JSON.stringify() 不能直接序列化 bigint。若接口约定将这些整数输出为十进制字符串,可在已知字段上明确转换:

function toApiRows(rows) {
  return rows.map(row => ({
    ...row,
    id: row.id.toString(),
  }));
}

该函数接收查询返回的行数组,在读取结果后调用,并让接收方按字符串处理标识符。示例只处理已知的 id 字段;查询若还有其他 INTEGER 列,也要逐项确定接口类型。不要给所有对象安装全局 BigInt 序列化补丁,悄悄改变整个服务的响应契约。

需要算术时,bigint 不能与 number 直接混算。时间字段还可能使用不同纪元或单位,成功读取并不代表能直接传给 Date。只有确认值处于安全整数范围、且业务允许转换时,才将它转为 number。

修正后核对原来失败的行能完整返回,标识符逐位一致,接口输出与下游存储也没有改回浮点数。这个过程不需要写库或改表;若撤回读取方式,应同时恢复调用方的类型与序列化约定,避免数据库层与接口层各用一套类型。