You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中如何将node-pg-stream查询分片追加到现有Excel工作表

实现方案

推荐依赖库

使用exceljs完成Excel写入需求,它支持流式追加数据,不会一次性加载整个工作簿到内存,完美适配大表导出场景,不会出现内存溢出问题。

完整实现代码

首先安装依赖:

npm install exceljs pg-query-stream

推荐使用异步迭代的写法,原生处理流的背压问题,代码更简洁:

const { Pool } = require('pg');
const QueryStream = require('pg-query-stream');
const ExcelJS = require('exceljs');

// 按你自己的业务配置修改PG连接参数
const pool = new Pool({
  user: '数据库用户名',
  host: '数据库地址',
  database: '数据库名',
  password: '数据库密码',
  port: 5432,
});

async function exportLargeTableToExcel() {
  const client = await pool.connect();
  try {
    // 1. 加载已有工作簿/新建工作簿
    const workbook = new ExcelJS.Workbook();
    // 若要追加到已存在的本地工作簿,取消注释下面代码替换成你的文件路径
    // await workbook.xlsx.readFile('你的现有工作簿路径.xlsx');
    // 获取指定工作表,不存在就新建
    const worksheet = workbook.getWorksheet('目标工作表名称') || workbook.addWorksheet('目标工作表名称');

    // 可选:新工作表可以提前配置列规则,已有工作表直接跳过即可
    // worksheet.columns = [
    //   { header: '字段1', key: 'db_column1', width: 15 },
    //   { header: '字段2', key: 'db_column2', width: 20 },
    //   // 和你查询的表字段一一对应即可
    // ];

    // 2. 初始化PG查询流
    const query = new QueryStream('select * from large_table');
    const stream = client.query(query);

    // 3. 流式处理数据追加
    for await (const data of stream) {
      worksheet.addRow(data);
      // 可选:每新增1000行刷入一次缓存,减少内存占用
      // if (worksheet.rowCount % 1000 === 0) {
      //   await workbook.xlsx.writeBuffer();
      // }
    }

    // 4. 全部数据处理完成后保存工作簿
    await workbook.xlsx.writeFile('最终输出的文件路径.xlsx');
    console.log('数据追加完成');

    // 若需要返回给前端下载,直接返回buffer即可
    // const buffer = await workbook.xlsx.writeBuffer();
    // res.type('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    // res.send(buffer);

  } catch (err) {
    console.error('处理出错:', err);
  } finally {
    client.release();
  }
}

exportLargeTableToExcel();

兼容原Event监听写法的代码

如果你不想改动原有代码的事件监听逻辑,直接替换data事件里的逻辑即可:

// 提前初始化好工作簿和目标工作表
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.getWorksheet('目标工作表') || workbook.addWorksheet('目标工作表');

const query = new QueryStream('select * from large_table');
const stream = client.query(query);

stream.on('end', async () => {
  await workbook.xlsx.writeFile('输出文件路径.xlsx');
  done();
  // 后续业务逻辑
});

stream.on('data', async (data) => {
  stream.pause();
  // 追加当前分片数据到工作表
  worksheet.addRow(data);
  stream.resume();
});

stream.on('error', (err) => {
  console.error('流处理出错', err);
  done();
});

优化建议

  • 批量写入性能更高,可攒500~1000条数据后调用worksheet.addRows(批量数据数组)一次性写入,比单条addRow性能高30%以上
  • 提前配置工作表的列规则,避免写入后列宽、字段匹配错误
  • 单表数据超过10万行建议拆分多个工作表存储,避免单个工作表过大打开卡顿

内容的提问来源于stack exchange,提问作者Ameer Dheyaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 06:54:03