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}.