我正在使用Sequelize将CSV文件中的数据导入Nodejs系统,但是我在尝试检查之前是否插入过上一行时遇到了问题。
这是我正在使用的代码
exports.insertEmployee = function (employee) {
return new Promise((fulfill, reject) => {
models.Employee.create(employee)
.then(employee => fulfill(employee.dataValues))
.catch(reject);
});
};
exports.importEmployee = function (employee) {
return new Promise((fulfill, reject) => {
models.Employee.findOne({where: {customID: employee.customID}, raw: true}).then(emp => {
if(emp) {
fulfill(emp);
}
else {
exports.insertEmployee(employee).then(fulfill);
}
});
});
};
函数importEmployee的调用次数与csv中的行数一样多次
lines.forEach(line => {
let emp = line.employee;
importEmployee(emp).then(employee => {console.dir(employee)});
});
我遇到的问题是,当我检查是否已经插入了具有相同customID的用户时,数据库尚未提交插入,因此它将始终返回false并且我将拥有重复的员工相同的customID
我怎么能解决这个问题?我尝试过使用交易,但也许我做错了,因为它无济于事。
谢谢!
答案 0 :(得分:2)
它不起作用,因为在forEach
内你想要执行一系列异步操作。这样就会插入所有记录,因为执行检查和插入的操作同时运行。为了避免这种情况,您可以使用Bluebird模块的mapSeries()
Promise函数。它内置于sequelize中,因此无需安装额外的包。
此外,您可以通过名为findOrCreate()
的单个操作执行检查和插入,该操作返回一个实例和布尔值,用于定义此实例是创建的还是仅作为现有实例返回。
当组合这两个功能时,您的操作变得非常简单和直接
// here is the function performing findOrCreate
exports.createEmployee = function(employee) {
return models.Employee.findOrCreate({
where: { customID: employee.customID },
defaults: employee
});
};
此外,您不必像在insertEmployee
和importEmployee
中那样创建嵌套的Promise。大多数sequelize函数已经返回promises,所以你可以简单地返回函数调用。
现在,您可以迭代lines
并调用createEmployee
方法。
models.sequelize.Promise.mapSeries(lines, (employee) => {
return createEmployee(employee);
}).then(result => {
console.log(result);
// example output: [ [ Instance, true ], [ Instance, true ], [ Instance, false ] ]
});
布尔值true
表示实例已创建,而false
表示实例是从表返回的,因为此类记录已存在。