node.js - 将 json 插入 Postgres 数据库时出现超时错误

标签 node.js postgresql sequelize.js bulkinsert

我想将我的文件插入到我的数据库中,其中包括对象数组(行)。我在 25 个文件夹中有近 8000 个文件和近 40000 条记录。

我收到 TimeoutError: ResourceRequest 超时。

我尝试增加 sequelize 的连接时间,但在前一千行后出现错误。如何正确有效地将 40000 行数据插入到我的本地数据库中?

let folders_path = path.join(__dirname, "extracted_subjects/*");

function bulk_insert() {
  glob(folders_path, readFolders);
}

function readFolders(err, folders) {
  if (err) {
    console.log("ERROR readFolders: ", err);
    return;
  }
  folders.forEach(function(file) {
    glob(path.join(file, "/*.json"), readFiles);
  });
}
function readFiles(err, files) {
  if (err) {
    console.log("ERROR readFiles: ", err);
    return;
  }
  files.forEach(async function(fileName) {
    //console.log(fileName);
    let promise = getData(fileName, "utf8")
      .then(data => {
        try {
          // Parse And Bulk Create
          let obj = JSON.parse(data);
          models.dream
            .bulkCreate(obj)
            .then(function() {
              console.log("File: inserted!");
            })
            .catch(err => console.log("Error", err));
        } catch (SyntaxError) {
          console.log("File: ", fileName);
          return;
        }
      })
      .catch(err => console.log(err));

    await promise;
  });
}

function getData(fileName, type) {
  return new Promise(function(resolve, reject) {
    fs.readFile(fileName, type, (err, data) => {
      err ? reject(err) : resolve(data);
    });
  });
}

最佳答案

您可以增加连接的默认设置,例如(您可以在文档中阅读这些设置):

    dialectOptions:   {
      timeout: 30
    },
    operatorsAliases: Sequelize.Op,
    pool:             {
      max:            5,
      min:            0,
      idle:           30000,
      maxConnections: 5,
      maxIdleTime:    30
    },

但我怀疑您最大的问题是您正在尝试读取所有文件并不断打开与数据库的新连接,而您没有时间将它们全部写入,它们自然会超时

我怀疑这种行为不是你想写的
files.forEach(async function (fileName) {
  let promise = getData(fileName, 'utf8');
    // ...
  await promise;
});

这部分代码使用了 async 和 await 这两个词,这并不是让它们顺序读取,它们仍然能够并行运行。您将尽可能快地调用 getData 函数,然后开始轰炸 models.dream.bulkCreatebulkCreate 的使用在这里也没有意义,因为您没有批量创建任何东西,而是一个一个地创建

我可以看到的选项是:

a) 保留类似的代码,但并行处理 25 x 25 个文件,每个块写入一次,这个变化有点大,在内存中读取 25 个,在数据库中批量写入它们,读取下一个 25 个,等等......
b) 保留类似的代码,但并行处理 25 x 25 个文件,每个块写入 25 次,这个变化有点大,打开并读取 25 个文件,然后每个文件只写入一行,然后继续
c) 保留类似的代码,但不是读取每个文件并将其写入数据库,而是将它们保存在内存中,并在获得所有数据后在最后写入所有数据一次。但是,在您使用大数据的情况下,您可能会耗尽内存
d) 如果性能不是问题,因为你想要/需要做一次(一段时间),你可以简单地循环所有文件并以同步模式读取它们,所以它总是一个一个地进行。
files.forEach(async function (fileName) {
  let data = fs.readFileSync(fileName, 'utf8'); // read the file sync

  try {
    let parsedData = JSON.parse(data); // try parsing
    models.dream                       // and inserting 
      .create(parsedData)              // this should not be bulkCreate, right??
       // this is kinda wrong, it doesn't automatically mean it 
       // is inserted, but it is copy paste from above
      .then(res => console.log('File: inserted!')) 
      .catch(err => console.log('Error', err));
  } catch (SyntaxError) {console.log('File: ', fileName);}
};

这段代码的作用是确保您按顺序逐个文件地执行,它会大大减慢您的执行速度,但是由于您最初表示要在本地主机上执行此操作,因此我认为您有时间离开它运行。您仍然冒着读取文件的速度比数据库可以处理的写入速度快的风险,但是这次与同步读取下一个文件应该没有太大区别,并且您的系统应该能够跟上,特别是如果您增加允许的数量池中的连接。

对于生产方面,我可能会选择 a 或 b 选项,这取决于我是否提前知道文件的最大大小/数量。

关于node.js - 将 json 插入 Postgres 数据库时出现超时错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54640554/

相关文章:

sql - 如何将其翻译成 postgresql?

node.js - (Sequelize) 按名称动态使用模型

javascript - 如何使用 sequelize 从 2 个表中查询信息

javascript - ShowSaveDialog默认扩展文件不起作用

node.js - 类型错误 : Cannot Read Property 'imageName' of undefined

javascript - 如何同时使用 Node js 中三个不同 API 调用的响应

postgresql - 如何找出 Postgres 中数据类型的可用性

node.js - Node.js 中带有回调的循环

sql - 带有 PostGis 的 Postgres 中的触摸功能

orm - 无法使用 sequelize cli 创建 ENUM 类型属性