Использование файла CSV в пакете node-sqlite3

Я использую нпм sqlite3 пакет в моем веб-приложении для макета ресторана (в учебных целях). В моей текущей реализации, когда мой локальный сервер запущен, я создаю menuItems таблица, вот так:

var db = new sqlite3.Database(':memory:');
db.serialize(function() {
  db.run('CREATE TABLE menuItems ('
          + 'itemName VARCHAR(255),'
          + 'itemDescription VARCHAR(255),'
          + 'unitPrice REAL'
          + ');')
  .run("INSERT INTO menuItems (itemName, itemDescription, unitPrice) VALUES"
          + " ('Fish Filet', 'Yummy fish in a sandwich.', 9.95)")
});

Тем не менее, я хотел бы для моего menuItems таблица не должна быть жестко закодирована в js файл и хотел бы, чтобы фактические элементы были отделены от этого js файл. Есть несколько решений, о которых я могу подумать:

  1. Используйте текущую реализацию и команды с жестким кодом для вставки отдельных элементов в таблицу.

  2. Используйте SQLite3 для импорта csv файл и вставьте его в таблицу.*

  3. Читать в пунктах от csv файл и вставьте их через цикл.

  4. Создайте базу данных до запуска сервера и передайте ее в sqlite3.Database() конструктор.

* Я хотел бы перейти к варианту 2. Однако, так как это для целей обучения, я открыт для любых предложений, включая, но не ограничиваясь, использование другого пакета управления базой данных или использование другого типа файла (может быть, просто txt файл или что-то).

Я знаю, что есть несколько способов импортировать csv файл с использованием SQLite3. Я пытаюсь сделать то же самое, но из sqlite3 Пакет Npm. Когда я пытаюсь импортировать файл с помощью той же команды (которая выглядит как команда, специфичная для sqlite3) со связанной страницы,

db.run('.import "C:/Users/path/to/csv/file.csv"'
      + 'INTO TABLE menuItems'
      + 'FIELDS TERMINATED BY ","'
      + 'ENCLOSED BY "\'"'
      + 'LINES TERMINATED BY \'\\n\''
      + 'IGNORE 1 ROWS'
      + ');');

Я получаю ошибку

events.js:183
  throw er; // Unhandled 'error' event
  ^

Error: SQLITE_ERROR: near ".": syntax error

Пытаясь использовать нормальный синтаксис SQL,

    .run('BULK INSERT menuItems'
          + 'FROM "C:/Users/path/to/csv/file.csv" '
          + 'WITH '
          + '{ '
          + 'FIRSTROW = 2,'
          + 'FIELDTERMINATOR = ","'
          + 'ROWTERMINATOR = "\n",'
          + 'ERRORFILE = "C:/Users/path/to/csv/error_file.csv" '
          + 'TABLOCK'
          + '}')

Я получаю ошибку

events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: SQLITE_ERROR: near "BULK": syntax error

Что-то в моем синтаксисе неверно? Есть ли лучший / рабочий / более эффективный способ сделать это? Вариант 3, похоже, сработает, но я еще не пробовал.

4 ответа

Решение

Я закончил с вариантом 3. А именно, я использовал fs пакет для чтения в CSV-файле, сделал некоторый анализ, вернул результаты в течение Promise объект, и сделал вставки базы данных в пределах then из сказанного Promise объект.

Есть небольшой пример для чтения вашего csv в sqlite3 db.

      const sql3 = require('better-sqlite3');
const   db = new sql3( 'memory.db' );
const  csv = require('csv-parser');
const   fs = require('fs');

// create table
db.exec( 'CREATE TABLE IF NOT EXISTS menuItems ( itemName TEXT, itemDescription TEXT, unitPrice REAL );' );
//db.exec( 'DROP TABLE menuItems;' );

const insrow = db.prepare( 'insert into menuItems ( itemName, itemDescription, unitPrice ) VALUES (?, ?, ?)' );


fs.createReadStream('C:/Users/path/to/csv/file.csv')
  .pipe(csv({"separator":";"}))
  .on('data', (row) => {
    
    insrow.run( row.itemName, row.itemDescription, row.unitPrice );
    console.log(row);
  })
  .on('end', () => {
    console.log('CSV file successfully processed');
    db.close();
  });
      

База данных в примере — memory.db, а формат csv — не через запятую, а через точку с запятой, измените разделитель, если это необходимо.

CSV в этом случае должен начинаться с заголовка itemName;itemDescription;unitPrice , а строка выглядит как Fish Filet;Вкусная рыба в бутерброде.;9,95 и так далее.

Пытаться

db.run('.import "C:/Users/path/to/csv/file.csv"'
      + 'INTO TABLE menuItems'
      + 'FIELDS TERMINATED BY ","'
      + 'ENCLOSED BY "\'"'
      + 'LINES TERMINATED BY \'\\n\''
      + 'IGNORE 1 ROWS'
      + ')');

команды, начинающиеся с . не нужно ставить точку с запятой в конце

  1. например, создайте файл file.csv, заголовок — это имена столбцов, строки — это записи, разделенные ; и строки в формате «строка» :

    itemName;itemDescription;unitPrice

    "Рыбное филе";"Вкусная рыбка в бутерброде.";9,95

2.1 Если типы столбцов не так важны, вы можете импортировать файл csv в базу данных с помощью file.sql3:

      .mode csv
.separator ";"
drop table if exists menuItems;
.import "file.csv" menuItems

2.2 запускаем импорт из nodejs:

      const { exec } = require('node:child_process');

exec('sqlite3 "memory.db" < "file.sql3"', (error, stdout, stderr) => {
    if (error) {
        console.error(`exec error: ${error}`);
        return;
    }
});

3.1 Если типы столбцов важны, вы можете импортировать файл csv в базу данных во временную таблицу tmp с помощью этого tmp.sql3 :

      .mode csv
.separator ";"
drop table if exists tmp;
.import "file.csv" tmp

3.2 запускаем импорт из nodejs:

      const { exec } = require('node:child_process');
const sql3 = require('better-sqlite3');   
exec('sqlite3 "memory.db" < "tmp.sql3"', (error, stdout, stderr) => {
    if (error) {
        console.error(`exec error: ${error}`);
        return;
    }
    const db = new sql3('memory.db');

    db.exec( "CREATE TABLE IF NOT EXISTS menuItems(" +
                        + 'itemName VARCHAR(255),'
                        + 'itemDescription VARCHAR(255),'
                        + 'unitPrice REAL'
                        + ');');
    db.exec("INSERT INTO menuItems " +
          + "select itemName, itemDescription, unitPrice from tmp;");
});
Другие вопросы по тегам