新手在使用 mongoose + js-xlsx 读取.xlsx文件并保存时遇到的一些问题
发布于 3 个月前 作者 Sily-P 494 次浏览 来自 问答

因需要读取excel文件并存进Mongodb,所以用了js-xlsx来操作excel文件,以下是我的代码:

var XLSX = require('xlsx')
var mongoose = require('mongoose')
mongoose.connect('mongodb://localhost/demo')
var Data = require('./dataModel')
var url = 'demo.xlsx'
function readExcelFile(url){
    var jsonData = []
    var workbook = XLSX.readFile(url)
    var sheetNames = workbook.SheetNames
    var sheets = workbook.Sheets
    var count = 0
    sheetNames.forEach(function(name){
        var sheet = sheets[name]
        if(!isEmptyObject(sheet)){
            var json = XLSX.utils.sheet_to_json(sheet)
            json.forEach(function(item){
                var data = new Data(item)
                data.save(function(err){
                    if(err){
                        console.log('保存失败!')
                        console.log(err)
                        return
                    }
                    console.log(item)
                    console.log('保存成功!')
                })
            })
            jsonData = jsonData.concat(json)
        }
    })
    return jsonData
}
readExcelFile(url)
mongoose.disconnect(function(err){
    if(err){
        console.log(err)
    }
    console.log('断开数据库连接...')
})
function isEmptyObject(e) {  
    var t;  
    for (t in e)  
        return !1;  
    return !0  
} 

这段代码是可以满足需求,但是控制台的最先输出的是 “断开数据库连接…”,然后才输出的是保存记录,一开始我想的是这输出记录的语句是在回调函数中,所以后输出。然后因需要操作.csv文件,我使用了ya-csv这个模块,以下是我的代码:

var csv = require('ya-csv');
var mongoose = require('mongoose')
mongoose.connect('mongodb://localhost/demo');
var DataModel = require('./dataModel');

function readfile(url){
	var reader = csv.createCsvFileReader(url, {columnsFromHeader:true, 'separator': ','});
	reader.on('data', function(data){
		var record = new DataModel(data);
		record.save(function(err){
						if(err){
							console.log('保存失败!');
							console.log(err);
							return;
						}
						console.log(record);
						console.log('保存成功!');
					});
	});
	reader.on('end', function(){
		console.log('Mission Complete!');
	});
	reader.on('error',function(){
		console.log('Mission Failed...');
	});
}

readfile('demo.csv');
mongoose.disconnect(function(err){
	if(err){
			console.log(err);
		}
		console.log('断开数据库连接...');
	});

基本思路和之前一样,但是这次虽然读取到了文件内容,但是无法保存进数据库中,若我不断开数据库连接,是可以成功保存的。难道是由于非阻塞式 I/O的原因数据库先于保存操作断开了(或者是更先于reader监听的data?)? 在操作excel文件是数据库断开的方法先于信息保存的回调方法执行的,为什么能保存成功?回调函数能保存数据库连接?对于这断开数据库的点我后来选择放到了reader监听的end中了,但此次遇到的问题还是很困扰,而且一般项目中,比如利用express生成的一个应用,应用中数据库一般是一直连接着吗?感觉断开的点不太好确定,会遇到类似这次的问题。小白对于很多还是不能理解,希望大神能给点指点。

7 回复

老老实实走异步的流程控。 “不要去想哪些代码是同步的哪些代码是异步的,但是这个世界终归是异步的。” —— jiangzhuo

这两种方案正确的做法都应该在所有保存数据的异步操作完成后再关闭数据库。 第一个方案中,文件里的数据被同步读取出来,有保存到数据的原因估计是数据量少或者数量只是部分被保存,因为数据库断开前也有可能一些保存操作已经完成。 至于第二个没保存到数据,是因为文件以流方式异步读取,创建流后就直接关闭了数据库,所以数据一个也没被保存到。

@jiangzhuo 对于异步流程控还不是很了解,继续学习 - -

@pauky 第一个根据控制台的输出信息,先输出了断开连接的信息,然后才输出了记录保存信息,而且我保存了近1万条数据,应该不是数据量少,数据也全部保存成功了。

@Sily-P 有可能mongo的断开不是强制的,得等任务队列执行完才断开。第一个方案已经将保存数据的任务提交到mongo的队列中,第二个方案只是在创建文件流后就断开了mongo。

@pauky 有道理,多谢多谢~

@Sily-P 只是我的猜测。正确的做法还是得等所有异步任务完成后再关闭mongo,具体可以试试promise或a或者async

回到顶部