每次插入后提交sequelize

时间:2017-03-08 10:16:05

标签: node.js sequelize.js

我正在使用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

我怎么能解决这个问题?我尝试过使用交易,但也许我做错了,因为它无济于事。

谢谢!

1 个答案:

答案 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
    });
};

此外,您不必像在insertEmployeeimportEmployee中那样创建嵌套的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表示实例是从表返回的,因为此类记录已存在。