
Sequelize предоставляет возможность не только строить запросы к базе данных на уровне моделей, но и извлекать фактический SQL, который будет выполнен. Это полезно для оптимизации запросов и отладки сложных операций. Методы модели, такие как findAll, findOne и update, принимают объект опций, где можно задать фильтры, сортировку и ассоциации.
Для получения SQL-запроса достаточно использовать метод Model.findAll с опцией logging или sequelize.dialect.QueryGenerator. Например, User.findAll({ where: { status: ‘active’ }, logging: console.log }) выведет точный SQL, соответствующий фильтру, без фактического выполнения запроса на чтение. Это позволяет тестировать конструкции JOIN и WHERE, проверяя их корректность.
Sequelize также позволяет конструировать запросы через QueryInterface и методы моделей для более сложных сценариев. Использование toSQL() или генераторов запросов обеспечивает точный контроль над структурой SQL, включая использование LIMIT, OFFSET и вложенных подзапросов. Такой подход ускоряет диагностику узких мест и предотвращает неожиданные нагрузки на базу данных.
Использование метода findAll для генерации SQL запроса

Метод findAll в Sequelize позволяет формировать SQL-запросы без непосредственного написания SQL. Для получения текста запроса достаточно передать опцию logging или использовать метод toSQL() у QueryInterface.
Простейший пример: Model.findAll({ where: { status: 'active' }, logging: console.log }). В консоль будет выведен сгенерированный SQL, включая фильтр по колонке status и таблицу, соответствующую модели.
Для сложных запросов findAll поддерживает ключи attributes, include, order и limit. Пример с выборкой конкретных полей и сортировкой:
Model.findAll({ attributes: ['id', 'name'], order: [['createdAt', 'DESC']], logging: console.log }). SQL будет содержать только указанные столбцы и соответствующее ORDER BY.
Для анализа сгенерированного SQL без выполнения запроса можно использовать транзакцию с откатом или метод sequelize.dialect.queryGenerator.selectQuery(Model.getTableName(), options), где options – объект с условиями findAll. Это позволяет проверить корректность фильтров, соединений и сортировки до обращения к базе.
Использование findAll совместно с raw: true возвращает объекты без обертки Sequelize, что упрощает сопоставление с исходным SQL и анализ его структуры.
Для оптимизации запросов рекомендуется явно указывать поля через attributes, ограничивать количество записей через limit и проверять условия where, чтобы генерируемый SQL был компактным и соответствовал бизнес-логике.
Формирование запроса с условиями через where

В Sequelize для фильтрации данных используется объект `where`, передаваемый в методы модели, такие как `findAll`, `findOne` или `update`. Каждое свойство объекта соответствует столбцу таблицы, а значение определяет условие выборки.
Простейший пример: `User.findAll({ where: { status: ‘active’ } })` вернёт всех пользователей с `status = ‘active’`. Для сложных условий применяются операторы из `Sequelize.Op`. Например, выборка пользователей старше 18 лет: `User.findAll({ where: { age: { [Op.gt]: 18 } } })`.
Объединение условий выполняется через `[Op.and]` и `[Op.or]`. Пример с комбинированной фильтрацией:
`User.findAll({ where: { [Op.and]: [{ status: ‘active’ }, { age: { [Op.gt]: 18 } }] } })` – вернёт активных пользователей старше 18 лет.
Для частичного совпадения строк применяется `[Op.like]` или `[Op.iLike]` в PostgreSQL:
`User.findAll({ where: { name: { [Op.like]: ‘%Ivan%’ } } })` – найдёт всех пользователей, у которых имя содержит «Ivan».
Для проверки принадлежности значения множеству используется `[Op.in]`:
`User.findAll({ where: { role: { [Op.in]: [‘admin’, ‘moderator’] } } })` – выбирает пользователей с ролями «admin» или «moderator».
Для диапазонов дат или чисел применяется `[Op.between]` и `[Op.notBetween]`:
`User.findAll({ where: { createdAt: { [Op.between]: [‘2025-01-01’, ‘2025-10-01’] } } })` – выбирает записи, созданные в указанном периоде.
Использование вложенных объектов `where` позволяет строить динамические запросы. Например, создание фильтра на основе входных параметров:
`const filter = {}; if(status) filter.status = status; if(minAge) filter.age = { [Op.gte]: minAge }; User.findAll({ where: filter })` – формирует запрос автоматически, учитывая только заданные условия.
С помощью `where` можно комбинировать точные совпадения, диапазоны, частичные строки и логические операторы для построения гибких запросов, без необходимости писать сырой SQL. Sequelize генерирует корректный SQL, учитывая синтаксис выбранной СУБД.
Получение SQL при включении связей через include

В Sequelize для анализа SQL-запросов с включением связанных моделей используется метод findAll, findOne или findByPk с опцией include. Для просмотра сгенерированного SQL применяется метод toSQL() или опция logging.
Пример запроса с включением связанной модели:
const users = await User.findAll({
include: [{ model: Profile, as: 'profile' }]
});
Для получения SQL без выполнения запроса можно использовать:
const query = User.findAll({
include: [{ model: Profile, as: 'profile' }],
logging: console.log,
raw: true
});
Особенности генерации SQL при include:
- Sequelize формирует
LEFT OUTER JOINпо умолчанию между основной и связанной таблицей. - Если указаны
attributesдля связанной модели, SELECT включает только эти поля, сокращая нагрузку на базу. - Вложенные
includeсоздают несколько JOIN, которые можно увидеть в сгенерированном SQL. - Для сложных условий рекомендуется использовать
whereвнутри include, чтобы фильтровать связанные записи на уровне SQL. - Псевдонимы
asдолжны совпадать с определением ассоциации, иначе JOIN не сформируется корректно.
Пример с вложенными связями и условиями:
const users = await User.findAll({
include: [{
model: Profile,
as: 'profile',
where: { active: true },
include: [{ model: Avatar, as: 'avatar' }]
}],
logging: console.log
});
Рекомендации при работе с include:
- Используйте
logging: console.logдля проверки JOIN перед интеграцией в код. - Ограничивайте SELECT через
attributes, чтобы уменьшить объем данных. - Для большого числа связей применяйте
separate: true, если нужны отдельные запросы для оптимизации. - Проверяйте соответствие ассоциаций и псевдонимов, чтобы избежать некорректного SQL.
В Sequelize агрегатные функции, такие как COUNT, SUM, AVG, MIN и MAX, можно вызвать через методы модели с использованием опции attributes и fn. Для получения SQL-запроса без выполнения операции используется метод Model.findAll с logging или sequelize.dialect.QueryGenerator.
Пример получения количества записей таблицы Users без выполнения запроса:
const query = User.findAll({ attributes: [[Sequelize.fn('COUNT', Sequelize.col('id')), 'total']] });
Чтобы вывести SQL, можно добавить logging в виде функции:
User.findAll({ attributes: [[Sequelize.fn('COUNT', Sequelize.col('id')), 'total']], logging: console.log });
На консоль будет выведен полный SQL-запрос вида: SELECT COUNT(`id`) AS `total` FROM `Users`;
Для сложных агрегатных запросов с фильтрацией и группировкой применяется group:
User.findAll({ attributes: ['role', [Sequelize.fn('SUM', Sequelize.col('salary')), 'total_salary']], group: ['role'], logging: console.log });
SQL будет: SELECT `role`, SUM(`salary`) AS `total_salary` FROM `Users` GROUP BY `role`;
Если требуется собрать агрегатные значения без выполнения запроса, можно использовать sequelize.dialect.QueryGenerator.selectQuery:
const sql = sequelize.dialect.QueryGenerator.selectQuery('Users', { attributes: [[Sequelize.fn('AVG', Sequelize.col('age')), 'average_age']] });
Это вернёт строку SQL SELECT AVG(`age`) AS `average_age` FROM `Users`; без обращения к базе данных.
Рекомендуется использовать logging для проверки корректности агрегатных функций и QueryGenerator для динамической генерации SQL на этапе разработки или отладки.
Логирование запроса при обновлении данных через update

В Sequelize метод update позволяет обновлять записи таблицы, но по умолчанию SQL-запрос не отображается в консоли. Для анализа или отладки запросов необходимо явно включить логирование.
Простейший способ – передать опцию logging:
await User.update({ name: 'Ivan' }, { where: { id: 1 }, logging: console.log });
В этом случае в консоль будет выведен полный SQL-запрос. Это особенно полезно при сложных условиях where или обновлении нескольких полей.
Если требуется централизованное логирование для всего проекта, в конфигурации Sequelize можно указать глобальный логгер:
const sequelize = new Sequelize(database, username, password, { logging: console.log });
Для детального анализа запросов можно использовать функции вместо console.log, чтобы сохранять SQL в файл или отправлять в систему мониторинга:
logging: (sql, timing) => { saveQueryToFile(sql, timing); }
Пример обновления с логированием и ограничением на количество обновляемых записей:
| Метод | Описание | Пример |
|---|---|---|
| update | Обновляет записи с учетом условия where |
await User.update({ age: 30 }, { where: { role: 'admin' }, logging: console.log }); |
| returning | Возвращает обновленные записи (Postgres) | await User.update({ active: true }, { where: { lastLogin: null }, returning: true, logging: console.log }); |
Важно учитывать, что при массовом обновлении update формирует один SQL-запрос, а не отдельный для каждой строки. Логирование позволяет точно видеть, какие поля и условия используются, предотвращая ошибки при сложных фильтрах.
Для динамического построения условий where рекомендуется проверять сформированный SQL через лог, чтобы убедиться в корректности синтаксиса и безопасности запросов.
Просмотр SQL при удалении записей через destroy
В Sequelize метод destroy используется для удаления записей из базы данных. Чтобы увидеть фактический SQL-запрос, выполняемый этим методом, необходимо включить логирование. Например, перед вызовом destroy можно использовать опцию logging:
await User.destroy({ where: { status: 'inactive' }, logging: console.log });
const sequelize = new Sequelize(database, username, password, { logging: console.log });
Важно учитывать, что метод destroy с параметром truncate: true формирует другой тип запроса – TRUNCATE TABLE, который не поддерживает условие WHERE и полностью очищает таблицу. Для выборочного удаления SQL-запрос всегда включает WHERE на основе переданных условий.
Для отладки сложных удалений с несколькими условиями рекомендуется сначала вывести запрос через Model.findAll({ where: {...}, logging: console.log }), чтобы проверить корректность условий перед вызовом destroy. Это снижает риск непреднамеренного удаления данных.
При работе с ассоциациями Sequelize также позволяет использовать каскадное удаление через опцию onDelete в модели, что отражается в сгенерированном SQL. Просмотр запроса через logging показывает все связанные DELETE-запросы для дочерних таблиц.
Использование logging позволяет анализировать производительность и выявлять потенциальные проблемы с индексацией при удалении больших объемов данных.
Вопрос-ответ:
Как получить SQL-запрос, который генерирует метод модели `findAll` в Sequelize?
В Sequelize можно увидеть SQL-запрос, создаваемый методом `findAll`, используя метод `getQuery()` через объект `Model.QueryGenerator` или выводя результат через `logging`. Например, при вызове `User.findAll({ where: { age: 25 }, logging: console.log })` Sequelize выведет готовый SQL-запрос в консоль. Это позволяет проверять, какой именно запрос будет выполнен, без его непосредственного исполнения на базе данных.
Можно ли получить SQL-запрос для метода `update` перед фактическим обновлением данных?
Да, можно. Для метода `update` можно передать параметр `logging`, который принимает функцию для обработки текста запроса. Например: `User.update({ name: ‘Иван’ }, { where: { id: 1 }, logging: console.log })`. В консоль будет выведен SQL-запрос, который выполняет обновление. Такой подход позволяет проверять корректность запроса перед внесением изменений в таблицу.
Есть ли способ получить SQL-запрос для метода `findOne` без его выполнения?
Прямого способа в Sequelize нет, но можно создать транзакцию с опцией `transaction.rollback()` после формирования запроса, чтобы отменить его выполнение, или использовать `sequelize.dialect.QueryGenerator` для генерации SQL вручную на основе параметров запроса. Это полезно для проверки структуры запроса перед запуском на реальной базе данных.
