从Sequelize文件中插入Node.js数据库

时间:2017-02-10 13:16:14

标签: mysql node.js csv asynchronous sequelize.js

也许我不完全理解承诺或Sequalize,但经过一段时间的努力,感觉异步数据库操作仅适用于更简单的情况。 并且通过询问同步数据库访问的问题数量,它看起来我不是唯一的。

这是我的情况。假设我们有含有化合物的CSV文件,其中每行包含有关化合物的信息,以及以分号分隔的成分列表。我们希望从中填充成分表,但没有重复。

例如,如果文件包含行

  

C1 IngA; IngB

     

C2 IngA; IngC

我们想要有三个记录的成分表,IngA,IngB和IngC。 因此,当读取行时,它应该保存化合物,对于每个成分检查是否已经存在,如果不存在则添加它。这是代码:

var lineReader=require('readline').createInterface({
  input: require('fs').createReadStream(filename)
});

lineReader.on('line', function(line) {

let parts=line.split('\t');
compoundModel.create({
  name: parts[0],
}).then(entity => {
  let ingredients=parts[1].split(';');

  ingredients.forEach((ing, index) => {
    ingModel.findOne({
      where: {name: ing}
    }).then(ingEntity => {
      if (ingEntity) {
        return ingEntity;
      }
      return ingModel.create({
        name: ing
      })
    });
  }).then(ingEntity => {
    //something else
  });
});
});    

问题是IngA被插入表中两次。我的猜测是,查找或创建Sequelize方法会返回promises,并且从文件中读取行的数据更快。因此,当读取新行并尝试找到IngA时,尚未插入第一行的IngA。

我尝试过几种方法,但对于这类任务来说,一切似乎都太复杂了。更重要的是,不起作用。

2 个答案:

答案 0 :(得分:1)

您需要使用锁定进行交易。

执行表级锁定以防止在您的情况下发生幻像读取

http://docs.sequelizejs.com/en/v3/api/transaction/

答案 1 :(得分:1)

请在解决方案之下,它应该有效。

var await = require('asyncawait/await');

var lineReader=require('readline').createInterface({
  input: require('fs').createReadStream(filename)
});

lineReader.on('line', function(line) {

let parts=line.split('\t');
compoundModel.create({
  name: parts[0],
}).then(entity => {
  let ingredients=parts[1].split(';');

  ingredients.forEach((ing, index) => {
        await(ingModel.findOrCreate({
          where: {name: ing}, defaults: {name: ing},
        }).spread(function(_record, _created){
        //Do something if required. _create will return true in case of entry already exists
        }))
  }).then(ingEntity => {
    //something else
  });
});
});    

在执行此操作前npm install asyncawait。在await的帮助下,它会等到承诺在执行下一个承诺之前完成它的执行。