Sequelize / -CLI с миграциями
Разбросанные детали из «Начало работы»
Более «полное» начало работы, охватывающее разбросанные / подводные камни документации Sequelize / -CLI.
GitHub: sequelize_getting_started
Если вы пришли с языка вроде Python или только начали использовать JavaScript, рано или поздно вам придется взаимодействовать с базой данных. Если вы разработчик на Python, возможно, вы использовали ORM, например SQLAlchemy или Django.
ORM означает объектно-реляционное управление, и это способ работы с вашей базой данных / таблицами так же, как с любым другим объектом, с которым вы будете программировать.
Когда вы используете JavaScript и начинаете искать ORM (SQL), Sequelize - это имя, которое вы будете часто встречать. Если вы когда-либо использовали Django, вы знаете, насколько легко выполняется миграция, а если вы еще не использовали, то вы «должно быть» потеряли много таблиц / баз данных.
Мне еще предстоит найти что-то сопоставимое с фреймворком Django, но sequelize - отличное место для начала и, похоже, вполне подходит для большинства задач, требуемых от ORM. Несмотря на то, что требуется больше ручного труда, возможная настройка стоит вашего времени, поскольку вы можете адаптироваться практически к любой ситуации.
Я не собираюсь больше тратить время на сравнение различных ORM друг с другом, вы должны исследовать это самостоятельно. Все, что я скажу, - после того, как я наконец разберусь с некоторыми странными частями, вы не ошибетесь, начав с Sequelize (если вы не используете документ db…).
«Поехали» (настройка):
Предположения:
- Вы знакомы с основами Node.js и NPM
- Вы знаете основы JavaScript
- Вы понимаете понятие ORM
В этом руководстве я буду следовать Sequelize CLI / документации по миграции, за исключением того, что дам вам все советы и приемы по мере продвижения, чтобы вам не пришлось прыгать вперед и назад в статьях / руководствах / документации, чтобы найти недостающие ссылки ( слава богу, когда я впервые использовал Sequelize, у меня был сверхширокий экран). Дело не в том, что документация Sequelize ужасна, она просто написана кем-то, кто знает, как использовать Sequelize. (По крайней мере, я так думаю ...)
NB: некоторые из этих команд не работают!
Я рекомендую вам набирать (или вставлять…) команды и код в том виде, в каком я их представляю. Таким образом, вы на собственном опыте столкнетесь с «подводными камнями», и, надеюсь, они сохранятся лучше.
Я не буду объяснять каждую команду, и ожидается, что вы будете искать функции / команды, если не понимаете, что они должны делать. Однако большинство (99%) довольно самоочевидны. (Не упомянутых вариантов много, но их легко найти позже)
Начнем с создания каталога, инициализации пакета npm и установки Sequelize / -CLI и нашего выбранного движка базы данных. Вы можете найти список движков БД и их пакетов здесь, но для простоты мы будем использовать sqlite в этом руководстве.
$ npm init -y
Если вы не хотите хранить весь свой код и конфигурацию в корневой папке (не…), нам нужно создать /src
каталог, и, поскольку мы не собираемся использовать фреймворк для этого руководства, давайте создадим простой index.js
в /src
каталоге .
В src/index.js
просто добавьте одну строчку:
console.log('Hello World!')
Теперь наш крошечный проект должен выглядеть так:
$ tree -I node_modules . ├── package.json ├── package-lock.json └── src └── index.js
Все идет нормально. Наша программа будет печатать строку… Позже мы получим эту строку из базы данных.
Теперь, когда наша «программа» настроена, пора перейти к реализации базы данных. Начнем с установки Sequalize / -CLI и движка базы данных:
$ npm i sequelize sequelize-cli sqlite3
Теперь, когда у нас установлены sequelize и sequelize-cli, у нас есть доступ к cli с исполнителем npm. Все, что нам нужно сделать, это инициализировать пустой проект.
Давайте сделаем это:
$ npx sequelize init
Затем давайте снова посмотрим на наш проект:
. ├── config │ └── config.json ├── migrations ├── models │ └── index.js ├── package.json ├── package-lock.json ├── seeders └── src └── index.js
О боже ... Это беспорядок ...
Sequelize предоставляет способ исправить это, добавив .sequelizerc
файл в корень нашего проекта. Итак, давайте удалим все файлы / папки, созданные sequelize, чтобы у нас остался наш исходный проект.
Затем давайте создадим .sequelizerc
файл в корне нашего проекта:
Не дайте себя обмануть отсутствующим расширением
.js
, вы можете написать простой JavaScript в этом файле.
Теперь давайте снова запустим init:
$ npx sequelize init
И давайте еще раз посмотрим на наш проект:
. ├── package.json ├── package-lock.json └── src ├── db │ ├── config │ │ └── config.js │ ├── migrations │ ├── models │ │ └── index.js │ └── seeders └── index.js
Теперь, если это не удовлетворяет ваше ОКР, ничто не будет ... Продолжаем, пора взглянуть на наш config.js
. Давайте откроем его и посмотрим:
{ "development": { "username": "root", "password": null, "database": "database_development", "host": "127.0.0.1", "dialect": "mysql" }, "test": { "username": "root", "password": null, "database": "database_test", "host": "127.0.0.1", "dialect": "mysql" }, "production": { "username": "root", "password": null, "database": "database_production", "host": "127.0.0.1", "dialect": "mysql" } }
Как видите, это не «JavaScript», а JSON (мы изменили название в .sequelizerc
). Давайте продолжим и исправим это, заменив контент на:
Файл конфигурации может быть
.json
или.js
Здесь происходит несколько вещей, но, как вы можете видеть, это в основном та же настройка, при которой мы экспортируем объект, за исключением того, что мы используем JavaScript для нашего пути и сокращенный синтаксис (ES6) для нашего хранилища. База данных будет храниться в нашем корневом каталоге.
Производственную среду мы не будем использовать в этом руководстве, но я счел ее важным включить, потому что это избавит вас от много головной боли, когда это «наступит время».
Если вы не пройдете
NODE_ENV
какproduction
илиtest
, Sequelize приметdevelopment
На этом мы завершаем настройку продолжения, теперь давайте перейдем к моделям.
«Самое интересное» (модели баз данных)
В этом руководстве мы будем придерживаться «скучных» моделей «пользователь / задача». Не из-за недостатка воображения, а из-за способности показывать отношения. Я покажу вам, как создать модель пользователя, которая .hasMany
(один-ко-многим) задач и модель задачи, которая .belongsTO
((один-к-одному) кто-то думает о профиле…)) пользователя.
Связи BelongsTo - это ассоциации, в которых внешний ключ для отношения «один-к-одному» существует в исходной модели
Ассоциации «один-ко-многим» (hasMany) соединяют один источник с несколькими целевыми объектами. Однако цели снова связаны точно с одним конкретным источником.
Я надеюсь, что когда вы закончите это руководство, у вас будет фундамент, который вам нужен, и вы сможете открыть Справочник по Sequelize API и найти другие варианты взаимоотношений.
Обычно вы заранее знаете, какие модели нуждаются в отношениях и какие. Итак, предположим, что мы это спланировали заранее. Если вы уже достигли той точки, в которой у вас есть модели, и теперь вы поняли, что вам нужны отношения, не волнуйтесь, просто следуйте инструкциям, и вы получите это.
Эти модели не предназначены для реального использования и максимально просты, чтобы не вносить ненужных сложностей.
Начнем с модели задачи:
$ npx sequelize model:generate --name Task --attributes taskName:string
Как видите, это довольно прямолинейно. Давайте продолжим и создадим нашу модель пользователей:
$ npx sequelize model:generate --name User --attributes name:string
Атрибуты модели и длину строки по умолчанию и т. Д. Можно посмотреть в документации.
Sequelize cli сгенерировал наши модели и файлы миграции, которые создают / обновляют нашу базу данных, экономя нам некоторую загрузку (и давая нам хороший API, с которым мы можем работать в нашем приложении, подробнее об этом позже).
Давайте еще раз посмотрим на наш проект:
. ├── package.json ├── package-lock.json └── src ├── db │ ├── config │ │ └── config.js │ ├── migrations │ │ ├── 20190611175237-create-task.js │ │ └── 20190611175246-create-user.js │ ├── models │ │ ├── index.js │ │ ├── task.js │ │ └── user.js │ └── seeders └── index.js
Наши модели сохраняются в папке src/db/models
(doh), а миграции - в папке src/db/migrations
(doubleDoh). Цифры, которые вы видите перед файлами миграции, являются отметками времени, поэтому sequelize будет знать, какой из них запускать в каком порядке (не так важно сейчас, но позже, при добавлении столбцов / таблиц…). Теперь src/db/seeders
это самое интересное. Sequelize предоставляет нам способ заполнения (предварительного заполнения) нашей базы данных, о чем я вскоре расскажу. Наконец, src/db/models/index.js
- это то, что мы импортируем в наше приложение узла, которое даст нам доступ к нашим моделям.
Теперь давайте продолжим и создадим / перенесем нашу базу данных:
$ npx sequelize db:migrate
Теперь у нас должен быть файл db.sqlite
в нашем корневом каталоге, содержащий наши таблицы. На данный момент наша база данных пуста, но давайте исправим это, создав семя для нашей базы данных:
$ npx sequelize seed:generate --name task
Теперь у нас есть новый файл в src/seeders
. Начнем с открытия {dateTime}-task.js
:
NB: обратите внимание на «Задачи» во множественном числе. Это потому, что мы ссылаемся на фактическую таблицу, а не на модель. Файлы миграции имеют одинаковый синтаксис, и это может немного сбивать с толку вначале.
Как видите, я добавил множество задач.
Пока мы будем ограничиваться только задачами, поскольку нет смысла добавлять пользователей, поскольку мы не можем назначать задачи пользователям на данный момент. Когда семя готово, давайте запустим его и заполним нашу базу данных:
$ npx sequelize db:seed:all
db:seed:all
запускает все начальные числа вsrc/db/seeds
, даже пустые (ничего не делает)
ERROR: Validation error
Итак, наше семя терпит неудачу ... Но мы следовали руководству ... И сообщение не очень помогает.
Вкратце: это означает, что наши данные не совпадают с нашими столбцами, а не с неправильными именами, база данных сообщает нам, что наши данные действительно проверяются. Давайте быстро взглянем на нашу базу данных (вам не нужно делать эту часть):
$ sqlite3 db.sqlite SQLite version 3.22.0 2018-01-22 18:45:57 Enter ".help" for usage hints. sqlite> .tables SequelizeMeta Tasks Users sqlite> .schema Users CREATE TABLE `Users` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL); sqlite> .schema Tasks CREATE TABLE `Tasks` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `taskName` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL); sqlite> SELECT * FROM SequelizeMeta; 20190611175237-create-task.js 20190611175246-create-user.js sqlite>
Вы можете увидеть наши таблицы вместе с SequelizeMeta, где sequelize отслеживает миграции. Но вы также можете видеть, что Sequelize добавила два столбца в нашу таблицу «Пользователи» и «Задачи». createdAt и updatedAt - это что-то, что sequelize добавляет автоматически, и мы должны добавить это в наше seed.
Если вы не хотите использовать createdAt и updatedAt, вам необходимо удалить их из файлов миграции модели перед первой миграцией. Удаление их после создания может быть выполнено с помощью другой миграции, о которой мы поговорим позже.
Давайте продолжим и добавим createdAt и updatedAt в наш файл миграции:
Теперь давайте снова запустим наши семена:
$ npx sequelize db:seed:all Sequelize CLI [Node: 11.15.0, CLI: 5.5.0, ORM: 5.8.9] Loaded configuration file "src/db/config/config.js". Using environment "development". == 20190611182947-task: migrating ======= == 20190611182947-task: migrated (0.030s) == 20190611182953-user: migrating ======= ERROR: Migration 20190611182953-user.js (or wrapper) didn't return a promise
Наша база данных теперь заполнена нашими тремя задачами.
Наконец, давайте внесем некоторые изменения в наш src/index.js
файл, чтобы мы могли получить доступ и распечатать данные из нашей недавно заполненной базы данных:
getTasksPromise()
и getgetTaksAsync()
делают то же самое. Я предпочитаю async await, но не всем он нравится / хочет / нравится, поэтому я решил написать и то, и другое.
Вверху мы импортируем src/db/models/index.js
, который является файлом, предоставленным Sequelize / -CLI. Затем Sequelize творит чудеса и перебирает наши модели, предоставляя нам db.Task
(а позже db.User
) API для работы.
db.Task.findAll()
- это обещание, которое вернет массив наших задач в виде объектов, с которыми мы можем работать, и в этом случае все, что мы делаем, - это перебираем их и выводим столбец taskName.
Запустим нашу программу:
$ node src/index.js Executing (default): SELECT `id`, `taskName`, `createdAt`, `updatedAt` FROM `Tasks` AS `Task`; Executing (default): SELECT `id`, `taskName`, `createdAt`, `updatedAt` FROM `Tasks` AS `Task`; This is task number one! This is task number two! This is task number three! This is task number one! This is task number two! This is task number three!
Посмотри на это! Мы выводим наши данные на консоль. Журнал, который вы видите вверху, - это Sequelize, печатающий запросы, которые мы отправили в консоль. Это можно отключить, установив параметр logging: false
, как показано на config.js
для производственного режима.
Прямо сейчас все, что у нас есть, - это две отдельные модели, которые не очень полезны, если они полностью не связаны. В нашем случае мы хотели бы связать задачи с отдельными пользователями, поэтому давайте продолжим это в разделе ассоциаций.
«Ручная часть» (Ассоциации)
К сожалению, мы не можем добавлять ассоциации через интерфейс cli Sequelize, нам нужно будет отредактировать модели, созданные для нас с помощью cli.
Давайте откроем и добавим нашу принадлежность в ассоциацию in/db/models/task.js
:
Как видите, здесь не так уж и много. Всего лишь «одна» строчка кода, и у нас есть наша ассоциация.
Код здесь довольно понятен, за исключением
foreignKey: "userId"
, который относится к столбцу, которого не существует в нашей модели задачи. Здесь будет храниться идентификатор пользователя (первичный ключ). Мы позаботимся об этом в ближайшее время.
Перейдем к нашей модели пользователей /db/models/user.js
и добавим hasMany:
Теперь у нас есть обновленные модели с ассоциациями, но для того, чтобы это работало, нам нужно обновить нашу таблицу задач и добавить столбец userId. Давайте сгенерируем для этого файл миграции:
$ npx sequelize migration:generate --name add-Task-userId-column
Теперь давайте откроем наш новый файл миграции {dateTime}-add-Task-UserId-column.js
и добавим новый столбец:
Помните, что при обращении к таблицам базы данных мы используем множественное число.
Вот и все, теперь у нас есть файл миграции и способ отслеживать наши миграции через интерфейс командной строки Sequelize. Не говоря уже о пути назад, если что-то пойдет не так с db:migrate:undo
. Давайте продолжим и применим нашу миграцию:
$ npx sequelize db:migrate Sequelize CLI [Node: 11.15.0, CLI: 5.5.0, ORM: 5.8.9] Loaded configuration file "src/db/config/config.js". Using environment "development". == 20190612212617-add-Task-userId-column: migrating ======= == 20190612212617-add-Task-userId-column: migrated (0.056s)
Большой! На этом мы закончили с нашими моделями и миграциями! Осталось только найти им хорошее применение. Давайте перейдем к этому в заключении.
«Конец…» (Заключение)
Давайте закончим включением некоторых основных методов модели в наш src/index.js
файл:
Я включил некоторые из основных вызовов, которые вы сделаете для sequelize api. Конечно, их гораздо больше, и все они доступны и описаны в документации.
- Добавление ownTo дает нам
.set<Model>
- Добавление hasMany дает нам
.get<Model>s
- Есть еще.
Ассоциации - хорошее место для их поиска.
Теперь вы можете спросить, нужна ли вся эта настройка и подготовка? Нет, конечно, нет, вы можете сделать все это в одном файле, но тогда у вас не будет вариантов миграции и возврата и т. Д. Здесь есть отличная статья, где вы можете увидеть, как все это сделать на JavaScript без каких-либо cli.
Итак, вам все это нужно. Нет, но теперь вы знаете, как это сделать, и достаточно знакомы с Sequelize, чтобы с легкостью понимать другие руководства и статьи. Взгляните на статью по ссылке выше, это хорошая отправная точка для установки всего JS!
Надеюсь, вы узнали что-то новое, и, пожалуйста, не стесняйтесь оставлять комментарии или вопросы.
/ Андерс