Как использовать SQLite с Node.js в Ubuntu 22.04
Автор выбрал программу Write for DOnations.
Введение
SQLite — это популярный механизм базы данных SQL с открытым исходным кодом для хранения данных. Он бессерверный, то есть для его работы не нужен сервер; вместо этого он читает и записывает данные в файл, который находится на диске компьютера. Кроме того, SQLite не требует никаких настроек; это делает его более портативным и популярным выбором для встраиваемых систем, настольных/мобильных приложений и прототипирования, среди прочего.
Чтобы использовать SQLite с Node.js, вам нужен клиент базы данных, который подключается к базе данных SQLite и отправляет операторы SQL из вашего приложения в базу данных для выполнения. Одним из популярных вариантов является пакет node-sqlite3
, предоставляющий асинхронные привязки для SQLite 3.
В этом руководстве вы будете использовать node-sqlite3
для создания соединения с базой данных SQLite. Далее вы создадите приложение Node.js, которое создает таблицу и вставляет данные в базу данных. Наконец, вы измените приложение, чтобы использовать node-sqlite3
для извлечения, обновления и удаления данных из базы данных.
Предпосылки
Чтобы следовать этому руководству, вам понадобятся:
- Среда разработки Node.js, настроенная в вашей системе. Если вы используете Ubuntu 22.04, установите последнюю версию Node.js, следуя варианту 3 нашего руководства «Как установить Node.js и создать локальную среду разработки».
- SQLite3 установлен в вашей среде разработки. Следуйте шагу 1 нашего руководства «Как установить и использовать SQLite в Ubuntu 20.04». Базовые знания о том, как создавать таблицы и писать SQL-запросы для извлечения и изменения данных в таблице. Выполните шаги со 2 по 6 нашего руководства Как установить и использовать SQLite в Ubuntu 20.04.
- Знакомство с тем, как написать программу Node.js, которую вы можете найти в нашем руководстве «Как написать и запустить свою первую программу в Node.js».
Шаг 1 — Настройка каталога проекта
На этом шаге вы создадите каталог проекта и загрузите node-sqlite3
в качестве зависимости.
Для начала создайте каталог с помощью команды mkdir
. Для этого руководства он называется sqlite_demo
, но вы можете заменить его на любое другое по вашему выбору:
- mkdir sqlite_demo
Затем перейдите во вновь созданный каталог с помощью команды cd
:
- cd sqlite_demo
Инициализируйте каталог проекта как пакет npm с помощью команды npm
:
- npm init -y
Команда создает файл package.json
, содержащий важные метаданные для вашего проекта. Параметр -y
указывает npm
принять все значения по умолчанию.
После выполнения команды на экране отобразится следующий вывод:
OutputWrote to /home/sammy/sqlite_demo/package.json:
{
"name": "sqlite_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Вывод указывает, что был создан файл package.json
, который содержит свойства, записывающие важные метаданные для вашего проекта. Некоторые из важных опций:
name
: название вашего проекта.версия
: версия вашего проекта.main
: отправная точка вашего проекта.
Вы можете оставить параметры по умолчанию такими, какие они есть, но не стесняйтесь изменять значения свойств в соответствии со своими предпочтениями. Для получения дополнительной информации о свойствах обратитесь к документации package.json npm.
Затем установите пакет node-sqlite3
с помощью npm install
:
- npm install sqlite3
После установки пакета вывод будет выглядеть следующим образом:
Outputadded 104 packages, and audited 105 packages in 9s
5 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Теперь, когда вы установили node-sqlite3
, вы будете использовать его для подключения к базе данных SQLite в следующем разделе.
Шаг 2 — Подключение к базе данных SQLite
На этом шаге вы будете использовать node-sqlite3
для подключения вашей программы Node.js к созданной вами базе данных SQLite, которая содержит различные акулы и их атрибуты. Чтобы установить соединение с базой данных, пакет node-sqlite3
предоставляет класс Database
. При создании экземпляра класса создается файл базы данных SQLite на диске вашего компьютера и подключается к нему. Как только соединение будет установлено, вы создадите таблицу для своего приложения, которую в следующих разделах вы будете использовать для вставки, извлечения или обновления данных.
Используя nano
или ваш любимый текстовый редактор, создайте и откройте файл db.js
:
- nano db.js
В файле db.js
добавьте следующий код, чтобы установить соединение с базой данных SQLite:
const sqlite3 = require("sqlite3").verbose();
const filepath = "./fish.db";
function createDbConnection() {
const db = new sqlite3.Database(filepath, (error) => {
if (error) {
return console.error(error.message);
}
});
console.log("Connection with SQLite has been established");
return db;
}
В первой строке вы импортируете модуль node-sqlite3
в файл программы. Во второй строке вы устанавливаете переменную filepath
с путем, по которому вы хотите, чтобы ваша база данных SQLite находилась, и именем файла базы данных, в данном случае это fish.db
.
В следующей строке вы определяете функцию createDbConnection()
, которая устанавливает соединение с базой данных SQLite. Внутри функции вы создаете экземпляр класса sqlite3.Database()
с ключевым словом new
. Класс принимает два аргумента: filepath
и обратный вызов.
Первый аргумент, filepath
, принимает имя и путь к базе данных SQLite, которой здесь является ./fish.db
. Второй аргумент — это обратный вызов, который запускается после создания базы данных и установления соединения с базой данных. Обратный вызов принимает параметр error
, который устанавливается в объект error
, если при попытке установить соединение с базой данных возникает ошибка. В обратном вызове вы используете оператор if
, чтобы проверить, есть ли ошибка. Если условие истинно, вы используете метод console.error()
для регистрации сообщения об ошибке.
Теперь, когда вы создаете экземпляр с помощью класса sqlite3.Database()
, он создает файл базы данных SQLite в каталоге вашего проекта и возвращает объект базы данных, который хранится в db
переменная. Объект базы данных предоставляет методы, которые можно использовать для передачи операторов SQL, создающих таблицы и вставляющих, извлекающих или изменяющих данные.
Наконец, вы вызываете console.log()
, чтобы зарегистрировать сообщение об успешном выполнении и вернуть объект базы данных в переменной db
.
Затем добавьте выделенный код для создания функции, создающей таблицу:
...
function createDbConnection() {
...
}
function createTable(db) {
db.exec(`
CREATE TABLE sharks
(
ID INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(50) NOT NULL,
color VARCHAR(50) NOT NULL,
weight INTEGER NOT NULL
);
`);
}
Функция createTable()
создает таблицу в базе данных SQLite. Он принимает объект базы данных db
в качестве параметра. В функции createTable()
вы вызываете метод exec()
объекта базы данных db
, который отправляет данный оператор SQL в базу данных для быть казненным. Метод exec()
используется только для запросов, которые не возвращают строки результатов.
Оператор SQL CREATE TABLE sharks...
, переданный методу exec()
, создает таблицу sharks
со следующими полями:
ID
: сохраняет значения типа данныхINTEGER
. ОграничениеPRIMARY KEY
назначает столбец первичным ключом, аAUTOINCREMENT
указывает SQLite автоматически увеличивать значения столбцаID
для каждой строки в таблице.name
: детализирует имя акулы, используя тип данныхVARCHAR
, содержащий не более 50 символов. ОграничениеNOT NULL
гарантирует, что поле не может хранить значения NULL.color
: представляет цвет акулы с использованием типа данныхVARCHAR
с максимальным количеством символов 50. ОграничениеNOT NULL
означает, что поле не должно принимать значения NULL.weight
: сохраняет вес акулы в килограммах с использованием типа данныхINTEGER
и использует ограничениеNOT NULL
, чтобы гарантировать, что значения NULL не допускаются.
В тот же файл db.js
добавьте выделенный код для вызова функции createTable()
:
function createDbConnection() {
const db = new sqlite3.Database(filepath, (error) => {
if (error) {
return console.error(error.message);
}
createTable(db);
});
console.log("Connection with SQLite has been established");
return db;
}
function createTable(db) {
...
}
При выполнении обратного вызова вы вызываете функцию createTable()
с объектом базы данных db
в качестве аргумента.
Затем добавьте следующую строку для вызова функции createDbConnection()
:
...
function createDbConnection() {
...
}
function createTable(db) {
...
}
module.exports = createDbConnection();
В предыдущем коде вы вызываете функцию createDbConnection()
, которая устанавливает соединение с базой данных и возвращает объект базы данных. Затем вы используете module.exports
для экспорта объекта базы данных, чтобы вы могли ссылаться на него в других файлах.
Теперь ваш файл будет содержать следующее:
const sqlite3 = require("sqlite3").verbose();
const filepath = "./fish.db";
function createDbConnection() {
const db = new sqlite3.Database(filepath, (error) => {
if (error) {
return console.error(error.message);
}
createTable(db);
});
console.log("Connection with SQLite has been established");
return db;
}
function createTable(db) {
db.exec(`
CREATE TABLE sharks
(
ID INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(50) NOT NULL,
color VARCHAR(50) NOT NULL,
weight INTEGER NOT NULL
);
`);
}
module.exports = createDbConnection();
Сохраните и выйдите из файла. При использовании nano
нажмите CTRL+X
, чтобы выйти, нажмите y
, чтобы сохранить внесенные изменения, и нажмите ENTER
для подтверждения имени файла.
Запустите файл db.js
с помощью команды node
:
- node db.js
Вывод покажет, что соединение с базой данных установлено успешно:
OutputConnection with SQLite has been established
Затем проверьте, был ли создан файл базы данных fish.db
с помощью команды ls
:
- ls
Outputdb.js fish.db node_modules package-lock.json package.json
Появление файла базы данных fish.db
в выходных данных подтверждает, что база данных была создана успешно.
Теперь каждый раз, когда вы запускаете файл db.js
, он будет вызывать функцию createTable()
для создания таблицы в базе данных. Попытка создать уже существующую таблицу приводит к тому, что SQLite выдает ошибку. Чтобы увидеть это, повторно запустите файл db.js
с помощью команды node
:
- node db.js
На этот раз вы получите сообщение об ошибке, показанное в следующем выводе:
OutputConnection with SQLite has been established
undefined:0
[Error: SQLITE_ERROR: table sharks already exists
Emitted 'error' event on Database instance at:
] {
errno: 1,
code: 'SQLITE_ERROR'
}
Node.js v17.6.0
Сообщение об ошибке указывает, что таблица sharks
уже существует. Это связано с тем, что при первом запуске команды node
создается база данных fish
, а также таблица sharks
. При повторном запуске команды функция createTable()
запускается снова во второй раз, что вызывает ошибку, поскольку таблица уже существует.
Эта ошибка также будет вызвана в любое время, когда вы захотите использовать методы объекта базы данных для управления базой данных в других файлах. Например, на следующем шаге вы создадите файл, который вставляет данные в базу данных. Чтобы использовать объект базы данных, вы импортируете файл db.js
и вызываете соответствующий метод для вставки данных в базу данных. Когда вы запускаете файл, он, в свою очередь, запускает db.js
, что вызывает ту же ошибку.
Чтобы исправить это, вы будете использовать метод existsSync()
модуля fs
для проверки существования файла базы данных fish.db
в каталог проекта. Если файл базы данных существует, вы установите соединение с базой данных без вызова функции createTable()
. Если он не существует, вы установите соединение и вызовете функцию createTable()
.
Для этого еще раз откройте db.js
в своем редакторе:
- nano db.js
В файле db.js
добавьте выделенный код для проверки существования файла базы данных:
const fs = require("fs");
const sqlite3 = require("sqlite3").verbose();
const filepath = "./fish.db";
function createDbConnection() {
if (fs.existsSync(filepath)) {
return new sqlite3.Database(filepath);
} else {
const db = new sqlite3.Database(filepath, (error) => {
if (error) {
return console.error(error.message);
}
createTable(db);
});
console.log("Connection with SQLite has been established");
return db;
}
}
Сначала вы импортируете модуль fs
, используемый для взаимодействия с файловой системой. Во-вторых, в добавленном операторе if
вы вызываете метод fs.existSync()
для проверки существования файла в заданном аргументе, который является файлом базы данных ./fish.db
здесь. Если файл существует, вы вызываете sqlite3.Database()
с путем к файлу базы данных и опускаете обратный вызов. Однако, если файл не существует, вы создаете экземпляр базы данных и вызываете функцию createTable()
в обратном вызове, чтобы создать таблицу в базе данных.
На этом этапе полный файл теперь будет отображаться следующим образом:
const fs = require("fs");
const sqlite3 = require("sqlite3").verbose();
const filepath = "./fish.db";
function createDbConnection() {
if (fs.existsSync(filepath)) {
return new sqlite3.Database(filepath);
} else {
const db = new sqlite3.Database(filepath, (error) => {
if (error) {
return console.error(error.message);
}
createTable(db);
});
console.log("Connection with SQLite has been established");
return db;
}
}
function createTable(db) {
db.exec(`
CREATE TABLE sharks
(
ID INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(50) NOT NULL,
color VARCHAR(50) NOT NULL,
weight INTEGER NOT NULL
);
`);
}
module.exports = createDbConnection();
Сохраните и закройте файл после внесения изменений.
Чтобы убедиться, что файл db.js
не выдает ошибку при многократном запуске, удалите файл fish.db
с помощью rm
команда, чтобы начать заново:
- rm fish.db
Запустите файл db.js
:
- node db.js
OutputConnection with SQLite has been established
Теперь убедитесь, что db.js
подключается к базе данных и не пытается снова создать таблицу для всех последующих повторных запусков файла db.js
, запустив файл снова:
- node db.js
Теперь вы заметите, что больше не будете получать ошибку.
Теперь, когда вы установили соединение с базой данных SQLite и создали таблицу, вы вставите данные в базу данных.
Шаг 3 — Вставка данных в базу данных SQLite
На этом шаге вы создадите функцию, которая вставляет данные в базу данных SQLite с помощью модуля node-sqlite3
. Вы передадите программе данные, которые хотите вставить, в качестве аргументов командной строки.
Создайте и откройте файл insertData.js
в текстовом редакторе:
- nano insertData.js
В файле insertData.js
добавьте следующий код для получения аргументов командной строки:
const db = require("./db");
function insertRow() {
const [name, color, weight] = process.argv.slice(2);
}
В первой строке вы импортируете объект базы данных, экспортированный в файл db.js
на предыдущем шаге. Во второй строке вы определяете функцию insertRow()
, которую вскоре будете использовать для вставки данных в таблицу. В этой функции process.argv
возвращает все аргументы командной строки в виде массива. Первый элемент по индексу 0
содержит путь к Node. Второй элемент в индексе 1
хранит имя файла программы JavaScript. Все последующие элементы, начиная с индекса 2
, содержат аргументы командной строки, которые вы передали в файл. Чтобы пропустить первые два аргумента, вы используете метод JavaScript slice()
, чтобы сделать неглубокую копию массива и вернуть элементы из индекса 2
в конец массива.
Затем добавьте выделенный код для вставки данных в базу данных:
const db = require("./db");
function insertRow() {
const [name, color, weight] = process.argv.slice(2);
db.run(
`INSERT INTO sharks (name, color, weight) VALUES (?, ?, ?)`,
[name, color, weight],
function (error) {
if (error) {
console.error(error.message);
}
console.log(`Inserted a row with the ID: ${this.lastID}`);
}
);
}
В предыдущем коде вы вызываете метод db.run()
, который принимает три аргумента: оператор SQL, массив и обратный вызов. Первый аргумент, INSERT INTO sharks...
, представляет собой инструкцию SQL, которая вставляет данные в базу данных. Оператор VALUES
в операторе INSERT
принимает список значений, разделенных запятыми, которые необходимо вставить. Обратите внимание, что вы передаете заполнители ?
вместо того, чтобы передавать значения напрямую. Это сделано для того, чтобы избежать атак путем внедрения SQL-кода. Во время выполнения SQLite автоматически заменит заполнители значениями, переданными во втором аргументе метода db.run()
, который представляет собой массив, содержащий значения аргументов командной строки.
Наконец, третий аргумент метода db.run()
— это обратный вызов, который запускается после успешной вставки данных в таблицу. В случае ошибки сообщение об ошибке регистрируется в консоли. Если вставка прошла успешно, вы регистрируете сообщение об успешном выполнении с идентификатором вновь вставленной строки, возвращенным this.lastID
.
Теперь добавьте выделенную строку для вызова функции insertRow()
:
const db = require("./db");
function insertRow() {
const [name, color, weight] = process.argv.slice(2);
db.run(
`INSERT INTO sharks (name, color, weight) VALUES (?, ?, ?)`,
[name, color, weight],
function (error) {
if (error) {
console.error(error.message);
}
console.log(`Inserted a row with the ID: ${this.lastID}`);
}
);
}
insertRow();
Сохраните и закройте файл, затем запустите файл с аргументами имени, цвета и веса акулы:
- node insertData.js sammy blue 1900
Вывод показывает, что строка была вставлена в таблицу с основным идентификатором 1
:
OutputInserted a row with the ID: 1
Запустите команду еще раз с другими аргументами:
- node insertData.js max white 2100
OutputInserted a row with the ID: 2
При выполнении предыдущих команд в таблице sharks
будут созданы две строки.
Теперь, когда вы можете вставлять данные в базу данных SQLite, теперь вы будете извлекать данные из базы данных.
Шаг 4 — Извлечение данных из базы данных SQLite
На этом шаге вы будете использовать модуль node-sqlite3
для извлечения всех данных, хранящихся в таблице sharks
в базе данных SQLite, и занести их в консоль.
Сначала откройте файл listData.js
:
- nano listData.js
В файле listData.js
добавьте следующий код для получения всех строк:
const db = require("./db");
function selectRows() {
db.each(`SELECT * FROM sharks`, (error, row) => {
if (error) {
throw new Error(error.message);
}
console.log(row);
});
}
Сначала вы импортируете объект базы данных в файл db.js
. Во-вторых, вы определяете функцию selectRows()
, которая извлекает все строки в базе данных SQLite. Внутри функции вы используете метод each()
объекта базы данных db
для извлечения строк из базы данных одну за другой. Метод each()
принимает два аргумента: оператор SQL и обратный вызов.
Первый аргумент SELECT
возвращает все строки в таблице sharks
. Второй аргумент — это обратный вызов, который запускается каждый раз, когда строка извлекается из базы данных. В обратном вызове вы проверяете наличие ошибки. Если есть ошибка, вы используете оператор throw
для создания пользовательской ошибки. Если во время извлечения ошибок не возникло, данные записываются в консоль.
Теперь добавьте выделенный код для вызова функции selectRows()
:
const db = require("./db");
function selectRows() {
db.each(`SELECT * FROM sharks`, (error, row) => {
if (error) {
throw new Error(error.message);
}
console.log(row);
});
}
selectRows();
Сохраните и выйдите из файла, затем запустите файл:
- node listData.js
После запуска команды вы увидите вывод, который выглядит следующим образом:
Output{ ID: 1, name: 'sammy', color: 'blue', weight: 1900 }
{ ID: 2, name: 'max', color: 'white', weight: 2100 }
На выходе отображаются все строки, которые вы вставили в таблицу sharks
на предыдущем шаге. Модуль node-sqlite3
преобразует каждый результат SQL в объект JavaScript.
Теперь, когда вы можете получать данные из базы данных SQLite, вы обновите данные в базе данных SQLite.
Шаг 5 — Изменение данных в базе данных SQLite
На этом шаге вы будете использовать модуль node-sqlite3
для обновления строки в базе данных SQLite. Для этого вы передадите программе аргумент командной строки, содержащий первичный идентификатор строки, которую вы хотите изменить, а также значение, до которого вы хотите обновить строку.
Создайте и откройте файл updateData.js
в текстовом редакторе:
- nano updateData.js
В файле updateData.js
добавьте следующий код для обновления записи:
const db = require("./db");
function updateRow() {
const [id, name] = process.argv.slice(2);
db.run(
`UPDATE sharks SET name = ? WHERE id = ?`,
[name, id],
function (error) {
if (error) {
console.error(error.message);
}
console.log(`Row ${id} has been updated`);
}
);
}
updateRow();
Сначала вы импортируете объект базы данных из файла db.js
. Во-вторых, вы определяете функцию updateRow
, которая обновляет строку в базе данных. Внутри функции вы распаковываете аргументы командной строки в переменные id
и name
. Переменная id
содержит основной идентификатор строки, которую вы хотите обновить, а name
содержит значение, которое должно отображаться в поле имени.
Затем вы вызываете функцию db.run()
со следующими аргументами: оператор SQL и обратный вызов. Оператор SQL UPDATE
изменяет столбец name
с текущего значения на значение, переданное в переменной name
. Предложение WHERE
гарантирует, что будет обновлена только строка с идентификатором в переменной id
. Метод db.run()
принимает второй аргумент, представляющий собой обратный вызов, который запускается после обновления значения.
Наконец, вы вызываете функцию updateRow()
.
Сохраните и закройте файл, когда закончите вносить изменения.
Запустите файл updateData.js
с id
строки, которую вы хотите изменить, и новым названием
:
- node updateData.js 2 sonny
OutputRow 2 has been updated
Убедитесь, что имя было изменено:
- node listData.js
Когда вы запустите команду, ваш вывод будет выглядеть следующим образом:
Output{ ID: 1, name: 'sammy', color: 'blue', weight: 1900 }
{ ID: 2, name: 'sonny', color: 'white', weight: 2100 }
Вывод показывает, что строка с идентификатором 2
теперь имеет sonny
в качестве значения поля name
.
Теперь вы можете обновить строку в базе данных. Далее вы удалите данные из базы данных SQLite.
Шаг 6 — Удаление данных в базе данных SQLite
В этом разделе вы будете использовать node-sqlite3
для выбора и удаления строки из таблицы в базе данных SQLite.
Создайте и откройте файл deleteData.js
в текстовом редакторе:
- nano deleteData.js
В файл deleteData.js
добавьте следующий код, чтобы удалить строку в базе данных:
const db = require("./db");
async function deleteRow() {
const [id] = process.argv.slice(2);
db.run(`DELETE FROM sharks WHERE id = ?`, [id], function (error) {
if (error) {
return console.error(error.message);
}
console.log(`Row with the ID ${id} has been deleted`);
});
}
deleteRow();
Сначала вы импортируете объект базы данных в файл db.js
. Во-вторых, вы определяете deleteRow()
, который удаляет строку в таблице sharks
. Внутри функции вы распаковываете идентификатор первичного ключа и сохраняете его в переменной id
. Затем вы вызываете db.run()
, который принимает два аргумента. Первый аргумент — это оператор SQL DELETE from sharks...
, который удаляет строку в таблице sharks
. Предложение WHERE
гарантирует, что будет удалена только строка с идентификатором в переменной id
. Второй аргумент — это обратный вызов, который запускается после удаления строки. В случае успеха функция регистрирует сообщение об успехе; в противном случае он регистрирует ошибку в консоли.
Наконец, вы вызываете функцию deleteRow()
.
Сохраните и закройте файл, затем выполните следующую команду:
- node deleteData.js 2
OutputRow with the ID 2 has been deleted
Затем подтвердите, что строка была удалена:
- node listData.js
Когда вы запустите команду, ваш вывод будет выглядеть примерно так:
Output{ ID: 1, name: 'sammy', color: 'blue', weight: 1900 }
Строки с идентификатором 2
больше нет в результатах. Это подтверждает, что строка была удалена.
При этом теперь вы можете удалять строки в базе данных SQLite с помощью модуля node-sqlite3
.
Заключение
В этой статье вы создали приложение Node.js, которое использует модуль node-sqlite3
для подключения и создания таблицы в базе данных SQLite. Затем вы изменили приложение для вставки, извлечения и обновления данных в базе данных. Наконец, вы изменили приложение, чтобы удалить данные из базы данных.
Дополнительные сведения о методах node-sqlite3
см. в серии статей How To Code in Node.js.