Knex/Node环境下用大JSON为PostgreSQL表做seed填充的问题咨询
解决方案
第一步:安装依赖
首先安装流式处理JSON需要的工具包:
npm install stream-json
第二步:重写工具函数,改为流式处理
原来的require导入JSON的方式会把整个文件一次性加载到内存,现在改成逐元素读取的流式方案,国家列表数据量小可以保留全量加载逻辑,不会造成内存压力:
const fs = require('fs') const { pipeline } = require('stream/promises') const StreamArray = require('stream-json/streamers/StreamArray') const { getCountries } = require('./helpers') // 替换为你实际的国家列表引入路径 // 导出异步迭代器,逐个输出格式化后的机场数据 async function* getAirportsStream() { const countryList = await getCountries() // 创建JSON文件读取流 const readStream = fs.createReadStream('./large-airport.json') // 初始化JSON数组流式解析器 const jsonStream = StreamArray.withParser() // 启动流管道,捕获异常 pipeline(readStream, jsonStream).catch(err => console.error('流解析出错:', err)) // 迭代解析出的每个数组元素 for await (const { value: airport } of jsonStream) { const { name, iata, icao, city, country, state, lat, lon, elevation, tz } = airport const countryDetails = countryList.find(({ code }) => code === country) // 输出格式化后的单条数据 yield { name, iata, icao, city, country: countryDetails?.name || country, // 加兜底避免无匹配时崩溃 state, latitude: lat, longitude: lon, timezone: tz, elevation } } }
第三步:修改seed文件,分批入库
使用分批插入的逻辑,避免单次提交大量数据给数据库造成压力:
const { getAirportsStream } = require('../helpers') exports.seed = async function (knex) { // 先清空目标表 await knex('airport').del() const BATCH_SIZE = 1000 // 每批插入条数,可根据服务器配置调整为1000-5000 let currentBatch = [] // 迭代流式输出的格式化数据 for await (const airport of getAirportsStream()) { currentBatch.push(airport) // 攒够一批就写入数据库 if (currentBatch.length >= BATCH_SIZE) { await knex('airport').insert(currentBatch) currentBatch = [] } } // 插入最后剩余的不足一批的数据 if (currentBatch.length > 0) { await knex('airport').insert(currentBatch) } }
可选优化
如果需要更高的插入性能,可以把普通insert替换为knex.batchInsert,用法完全一致,批量写入效率更高。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

