SQL¶
Для работы Node.js с базами данных SQL используется модуль sequelize.
1 |
|
Node.js sequelize поддерживает следующие СУБД: MySQL, PostgreSQL, MSSQL и MariaDB.
Модуль имеет единое API для всех перечисленных СУБД, поскольку все перечисленные СУБД используют единый язык описания запросов - SQL.
Подключение¶
Рассмотрим подключение к базе данных PostgreSQL.
connection.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Во всех последующих примерах будет подразумеваться, что переменная sequelize
хранит соединение с БД.
За подключение отвечает класс Sequelize
, при создании экземпляра которого задаются следующие параметры:
- имя базы данных, к которой необходимо подключиться;
- имя пользователя;
- пароль;
- объект конфигурации.
Через объект конфигурации можно задать множество параметров, вот лишь некоторые из них:
host
- хост сервера БД (по умолчаниюlocalhost
);port
- порт сервера БД (по умолчанию порт по умолчанию выбранной СУБД);dialect
- тип используемой СУБД (mariadb
,mysql
,mssql
,postgres
);pool
- настройка пула соединений;scheme
- используемая схема (по умолчаниюnull
).
Пример настройки пула соединений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
С полным перечнем задаваемых опций можно ознакомиться в документации Node.js sequelize.
Для проверки установки соединения в примере вызывается метод authenticate()
, который возвращает объект Promise
.
1 2 3 4 5 6 |
|
Не открывайте новое соединение пока не закроете текущее.
Модели¶
Модели используются для описания структуры таблицы. Одна модель описывает одну таблицу.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Модель создается с помощью метода init()
класса, который является дочерним по отношению к Sequelize.Model
. Метод init()
принимает два объекта:
- объект с описанием полей таблицы;
- конфигурация создаваемой модели и соответствующей ей таблицы.
Описание поля задается объектом со следующими свойствами:
type
- тип поля;defaultValue
- значение поля по умолчанию;primaryKey
- булевое значение, еслиtrue
, то поле является первичным ключом (по умолчаниюfalse
);autoIncrement
- булевое значение, еслиtrue
, то при добавлении новой записи значение поля будет значение предыдущей записи этого поля плюс единица (по умолчаниюfalse
);allowNull
- булевое значение, еслиfalse
, запрещает создавать новую запись с этим пустым полем;unique
- булевое значение, еслиtrue
, то значение указанное для этого поля в записи должно быть уникальным в пределах таблицы (по умолчаниюfalse
);comment
- комментарий к полю;field
- если указано, то в качестве названия поле будет использоваться именно это значение, а не ключ;validate
- объект с заданием для поля валидаторов, с полным списком можно ознакомиться в документации;get()
- функция, которая модифицирует значение поля при чтении записи;set()
- функция, преобразующая передаваемое значение при сохранении записи.
get.js
1 2 3 4 5 6 7 |
|
Реализация аналогичного функционала с использованием set()
.
set.js
1 2 3 4 5 6 7 |
|
Конфигурация модели (второй параметр, передаваемый init()
) описывается следующим объектом:
modelName
- имя модели;timestamps
- булевое значение, еслиtrue
, то к таблице автоматически будут добавлены поляcreatedAt
(дата и время создания записи) иupdatedAt
(дата и время обновления записи);paranoid
- булевое значение, еслиtrue
, то вместо фактического удаления записи добавит полеdeletedAt
с датой и временем выполнения запроса на удаление (работает совместно с{timestamps: true}
);underscored
- булевое значение, еслиtrue
, то названия полей будут переименованы с использованием символа нижнего подчеркивания, например, если поле названоauthorName
, то в таблице оно фактически будет называтьсяauthor_name
(параметр не распространяется на значение поляfield
, указанное при описании поля таблицы);freezeTableName
- булевое значение, еслиtrue
, то название таблицы будет таким, как указано вtableName
(по умолчанию названия всех таблиц преобразуются в множественное число);tableName
- название таблицы;hooks
- определение триггеров (рассмотрены отдельно далее);indexes
- определение индексов (рассмотрены отдельно далее);sequelize
- экземпляр объекта активного соединения с БД.
Если описанной с помощью модели таблицы физически еще не существует, она будет создана автоматически в момент запуска приложения или вызова метода sync()
в уже работающем приложении.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Создание связей¶
Создание связей между таблицами осуществляется с использованием моделей. Рассмотрим установление следующих типов связей:
- один к одному;
- один ко многим;
- многие ко многим.
Пример установки связи один к одному.
one-to-one.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
Определение связи один к одному подразумевает, что у одного водителя имеется одна машина.
Разница между использованием belongsTo()
и hasOne()
в том, что в первом случае foreignKey
будет добавлен в модель Car
, а во втором - в модель Driver
.
По умолчанию формат добавляемого foreignKey
следующий: modelName + "Id"
. Так, belongsTo()
добавит в Car
поле driverId
, а hasOne()
- в Driver
поле carId
.
Если вы хотите задать собственное наименование foreignKey
или связать таблицы не по полю id
, используйте следующий формат определения связи.
1 2 3 4 |
|
Значение поля sourceKey должно быть уникальным.
Теперь рассмотрим пример установки связи один ко многим. В качестве исходных моделей используем модели из примера связи один к одному.
1 2 |
|
Здесь в примере определение связи один ко многим указывает, что у одного водителя может быть несколько машин.
Если необходимо указать пользовательские поля связывания, то придется указать полную связь.
1 2 3 4 5 6 7 8 |
|
Теперь посмотрим, как определить связь многие ко многим на примере все тех же моделей Car
и Driver
.
1 2 |
|
Для хранения соответствия ключей водителей и автомобилей будет создана отдельная таблица, название которой указывается в поле through
объекта, передаваемого методу belongsToMany()
вторым параметром.
Задание полей в создаваемой таблице можно указать через свойство foreignKey
.
1 2 3 4 5 6 7 8 |
|
Пример извлечения данных из таблицы вместе с данными связанной таблице приведен далее в разделе "Получение/создание/обновление/удаление записи".
Если необходимо, чтобы модель CarDriver
содержала дополнительные поля, просто заранее определите модель с этими самыми полями. Поля car_id
и driver_id
будут добавлены автоматически в момент создания связи.
1 2 3 4 5 6 7 8 9 10 11 |
|
Получение/создание/обновление/удаление записи¶
Для получения данных таблицы, применительно к соответствующей модели используйте методы findAll()
и findOne()
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
С полным списком поддерживаемых Node.js sequelize операторов можно ознакомиться на официальном сайте.
Создание новых записей осуществляется с помощью методов create()
и bulkCreate()
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
За обновление записей отвечает метод update()
, который первым параметром принимает новые значения для записей, попадающих под задаваемую вторым параметром выборку.
1 2 3 4 5 6 7 8 9 10 |
|
Для удаления записей имеется метод destroy()
.
1 2 3 4 5 |
|
Для выполнения самописных запросов без использования модели таблицы имеется метод sequelize.query()
, который первым параметром принимает сам запрос в строковом виде, а вторым параметром - конфигурационный объект.
1 2 3 4 5 6 |
|
Триггеры¶
Триггеры представляют собой функции, которые выполняются (если они определены) до/после/во время действий с данными. Список самых популярных триггеров в порядке их выполнения:
beforeValidate(данные, опции)
- выполняется перед валидацией;afterValidate(данные, опции)
илиvalidationFailed(данные, опции, ошибка)
- выполняется после успешной или неуспешной проверки валидации соответственно;beforeCreate(данные, опции)
- вызывается перед созданием записи;beforeDestroy(данные, опции)
- выполняется перед удалением записи;beforeUpdate(данные, опции)
- вызывается перед обновлением записи;beforeSave(данные, опции)
- вызывается перед сохранением записи;afterCreate(данные, опции)
- вызывается после создания записи;afterDestroy(данные, опции)
- выполняется после удаления записи;afterUpdate(данные, опции)
- вызывается после обновления записи;afterSave(данные, опции)
- вызывается после сохранения записи.
Определение триггеров осуществляется в модели таблицы в объекте конфигурации в свойстве hooks
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Также имеется пара триггеров beforeConnect()
и afterConnect()
для подключения к БД.
1 2 3 4 5 6 7 8 |
|
С полным перечнем триггеров можно ознакомиться в официальной документации.
Индексы¶
Создание индексов осуществляется при создании модели таблицы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Если не указать у составного индекса поле name, то по умолчанию его именем будет ${table}_${fields}
.