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

Posted

技术标签:

【中文标题】使用 Sequelize 从文件插入 Node.js 数据库【英文标题】:Node.js database insertion from a file with Sequelize 【发布时间】:2017-06-28 20:35:57 【问题描述】:

也许我不完全理解 Promise 或 Sequalize,但在使用它一段时间后,感觉异步 DB 操作仅适用于更简单的情况。 从要求同步数据库访问的问题数量来看,我不是唯一一个。

这是我的情况。假设我们有一个包含化合物的 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 被插入到表中两次。我的猜测是 find 或 create Sequelize 方法返回承诺,并且从文件中读取行比插入数据库更快。因此,当读取新行并尝试找到 IngA 时,尚未插入第一行的 IngA。

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

【问题讨论】:

分步做怎么样?读取数组中的所有值,去除重复项并执行bulkCreate操作。 正是我目前正在做的事情:)。但它需要两次遍历整个文件,并且处理不是流式处理 - 在内存中保存大的 Set 对象,因为 CSV 文件可以有 400K 行。希望有更好的选择,这是常见的数据输入任务。 【参考方案1】:

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

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

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

【讨论】:

谢谢,我会尝试这种方法,目前按照 piotrbienias 的建议实施。【参考方案2】:

请在下面的解决方案中很好,它应该可以工作。

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 的帮助下,它会等到promise 完成执行后再执行下一个promise。

【讨论】:

以上是关于使用 Sequelize 从文件插入 Node.js 数据库的主要内容,如果未能解决你的问题,请参考以下文章

由于带有 sequelize.js 的 UUID 外键,尝试将行插入表时出错

尝试将行插入表因为带有sequelize.js的UUID外键时出错

使用 Node.js/Sequelize 进行批量插入时 PostgreSQL 崩溃

Sequelize 6 从文件中导入模型

如何使用 Sequelize 和 node.js 进行批量插入

Sequelize:批量插入