Node.js将Excel数据转JSON并存储到MongoDB失败问题求解
问题原因
- 异步执行顺序错误:Excel文件读取是流式异步操作,数据库连接也是异步操作。现有代码中调用
readFile()后立刻执行insertDb(),此时Excel还未完成读取,finalList是空数组,同时数据库连接大概率还未建立完成,插入操作自然无效,大文件场景下这个问题会更明显。 - 对象引用错误:
singlePerson是全局定义的对象,每次循环处理行数据时都是修改同一个对象的属性,最终finalList中存储的全是同一个对象的引用,所有元素都会被覆盖为最后一行的数据,即使插入成功数据也是错的。 - MongoDB插入逻辑错误:现有插入代码中
new obj(list)是创建单个文档,你传入的list是数据数组,会被当做单个文档的属性存储,不符合需求;且save()是异步方法,没有捕获错误回调,执行失败也不会抛出提示。 - 大文件内存溢出风险:你把所有Excel行都存在
finalList数组里,如果Excel行数极多,会导致内存占用过高甚至进程崩溃,还没到插入步骤程序就已经静默退出。
修复方案
1. 调整异步执行顺序
把插入数据库的操作放到Excel读取完成的end事件回调中,且确保数据库连接成功后再开始读取Excel文件。
2. 修复对象引用问题
每次处理行数据时都重新创建新的singlePerson对象,避免引用覆盖。
3. 修正MongoDB插入逻辑
使用insertMany批量插入数组文档,添加异步错误捕获,方便定位问题。
4. 优化大文件处理
如果Excel文件超过10万行,建议分批插入,每读1000行就插入一次,避免内存占用过高。
修改后代码
excel2.js
const XlsxStreamReader = require("xlsx-stream-reader"); var fs = require('fs'); const config = require('./excelpush.json'); const db = require('./dbmanager.js'); class ExcelReader { async readFile() { // 先等待数据库连接成功 await db.connectDb(); const workBookReader = new XlsxStreamReader(); let finalList = []; // 每批插入1000条,大文件可以调整这个数值 const BATCH_SIZE = 1000; workBookReader.on('error', function (error) { throw error; }) workBookReader.on('worksheet', function (workSheetReader) { if (workSheetReader.id > 1) { workSheetReader.skip(); return; } let isFirstLine = true; let headerIndex = []; workSheetReader.on('row', async function (row) { if (isFirstLine) { headerIndex = row.values.slice(1); } else { const rowValues = row.values.slice(1); // 每次新建对象,避免引用覆盖 const singlePerson = {}; headerIndex.forEach((currentval, index) => { singlePerson[currentval] = rowValues[index]; }); finalList.push(singlePerson); // 达到批量阈值就先插入一次,清空数组释放内存 if (finalList.length >= BATCH_SIZE) { // 暂停流处理,等插入完成再继续,避免背压 workSheetReader.pause(); await db.insertDb(finalList); finalList = []; workSheetReader.resume(); } } isFirstLine = false; }); workSheetReader.on('end', async function () { // 插入剩余不足一批的数据 if (finalList.length > 0) { await db.insertDb(finalList); } console.log('所有数据插入完成!'); // 插入完成后关闭数据库连接 await db.closeDb(); }); workSheetReader.process() }); workBookReader.on('end', function () { console.log('Excel文件读取完成!'); }); fs.createReadStream(config.filePath).pipe(workBookReader); } } const excelReader = new ExcelReader(); excelReader.readFile().catch(err => console.log('运行出错:', err));
dbmanager.js
var mongoose = require('mongoose'); const config = require('./db.json'); // 缓存model,避免重复创建 let dataModel = null; async function connectDb() { return new Promise((resolve, reject) => { mongoose.connect(`mongodb://${config.dbConfig.host}:${config.dbConfig.port}/${config.dbConfig.dbName}`); mongoose.connection.once('open', function () { console.log('数据库连接成功'); // 提前创建model,避免重复生成 const myschema = new mongoose.Schema({}, { strict: false }); dataModel = mongoose.model('ExcelData', myschema, config.dbConfig.collectionName); resolve(); }).on('error', function (error) { console.log('数据库连接错误:' + error); reject(error); }) }) } async function insertDb(list) { try { // 批量插入数据 await dataModel.insertMany(list); console.log(`成功插入${list.length}条数据`); } catch (err) { console.log('插入数据出错:', err); throw err; } } async function closeDb() { await mongoose.connection.close(); console.log('数据库连接已关闭'); } module.exports = { connectDb, insertDb, closeDb }
现有db.json、excelpush.json配置文件无需修改。
内容的提问来源于stack exchange,提问作者Shakti Swarup Swain
相关产品推荐
相关产品推荐

