Sequelize.js: як використовувати міграції та синхронізацію


137

Я близький до того, щоб мій проект був готовий до запуску. У мене є великі плани після запуску, і структура бази даних буде змінюватися - нові стовпці в існуючих таблицях, а також нові таблиці та нові асоціації з існуючими та новими моделями.

Я ще не торкнувся міграції в Sequelize, оскільки у мене були лише дані тестування, які я не проти витирати щоразу, коли змінюється база даних.

З цією метою в даний час я працюю sync force: trueпри запуску програми, якщо я змінив визначення моделі. Це видаляє всі таблиці та робить їх з нуля. Я можу пропустити forceваріант, щоб він створював лише нові таблиці. Але якщо існуючі змінилися, це не корисно.

Отже, як тільки я додаю під час міграції, як все працює? Очевидно, я не хочу, щоб існуючі таблиці (з даними в них) були вилучені, тому питання не sync force: trueвиникає. В інших програмах, які я допомагав розробляти (Laravel та інші рамки) в рамках процедури розгортання програми, ми запускаємо команду migrate для запуску будь-яких очікуваних міграцій. Але в цих додатках найперша міграція має скелетну базу даних, із базою даних у тому стані, де це було деякий час на початку розробки - перший альфа-реліз чи що завгодно. Тож навіть екземпляр програми, що спізнюється з учасником, може швидко набирати швидкість, запускаючи всі міграції послідовно.

Як створити таку "першу міграцію" в Sequelize? Якщо у мене його немає, новий екземпляр програми, який-небудь вниз по лінії, або не матиме бази даних скелета для запуску міграцій, або він запустить синхронізацію на старті і зробить базу даних у новому стані з усіма нові таблиці тощо, але тоді, коли він намагається запустити міграцію, вони не матимуть сенсу, оскільки вони були написані з оригінальною базою даних та кожною послідовною ітерацією на увазі.

Мій розумовий процес: на кожному етапі початкова база даних плюс кожна міграція в послідовності повинна дорівнювати (плюс або мінус даних) базі даних, що створюється при sync force: trueзапускається. Це тому, що описи моделей у коді описують структуру бази даних. Тож, можливо, якщо немає таблиці міграції, ми просто запустимо синхронізацію і позначимо всі міграції як виконані, навіть якщо вони не були запущені. Це те, що мені потрібно зробити (як?), Або Sequelize повинен зробити це сам, або я гавкаю неправильне дерево? І якщо я перебуваю в потрібній зоні, то, безумовно, повинен бути хороший спосіб автоматичної генерації більшої частини міграції, враховуючи старі моделі (за допомогою хеш-файлу? Або навіть можна, щоб кожна міграція була прив’язана до фіксації? Я визнаю, що думаю у непереносному всесвіті git) та нових моделях. Він може відрізняти структуру та генерувати команди, необхідні для перетворення бази даних зі старої в нову та назад, і тоді розробник може зайти та зробити будь-які необхідні зміни (видалення / перехід конкретних даних тощо).

Коли я запускаю sequelize binary з --initкомандою, вона дає мені порожній каталог міграцій. Коли я запускаю, sequelize --migrateце робить мені таблицю SequelizeMeta, в якій немає нічого, немає інших таблиць. Очевидно, що ні, тому що цей двійковий не знає, як завантажувати додаток і завантажувати моделі.

Я, мабуть, чогось пропускаю.

TLDR: як я можу налаштувати додаток та його міграцію, щоб можна було оновити різні екземпляри програми, а також абсолютно новий додаток без застарілої стартової бази даних?


2
Я відповів, що стосується вашого робочого процесу, але в ідеалі всі таблиці повинні бути налаштовані за допомогою міграції. Навіть якщо ви зараз використовуєте sync, ідея полягає в тому, що міграції "генерують" всю базу даних, тому покладання на скелет сама по собі є проблемою. Наприклад, робочий процес Ruby on Rails використовує Міграцію для всього, і це досить приголомшливо, коли ви звикаєте до нього. Редагувати: І так, я помітив, що це питання досить старе, але, побачивши, що ніколи не було задовільної відповіді, і люди можуть прийти сюди шукати настанови, я подумав, що я повинен зробити свій внесок.
Фернандо Кордейро

Відповіді:


88

Створення "першої міграції"

У вашому випадку найнадійніший спосіб - це зробити майже вручну. Я б запропонував використовувати інструмент sequelize-cli . Синтаксис досить простий:

sequelize init
...
sequelize model:create --name User --attributes first_name:string,last_name:string,bio:text

Це створить і модель І міграцію. Потім вручну з’єднайте існуючі моделі з створеними за допомогою sequelize-cli і зробіть те ж саме з міграціями. Після цього протріть базу даних (якщо можливо) та запустіть

sequelize db:migrate

Це створить схему міграцій. Ви повинні зробити це лише один раз, щоб перейти до належного процесу розробки схем (без синхронізації: сила, але з авторитетними міграціями).

Пізніше, коли вам потрібно змінити схему:

  1. Створіть міграцію: sequelize migration:create
  2. Запишіть функції вгору та вниз у міграційний файл
  3. Відповідно до змін у файлі міграції, змініть свою модель вручну
  4. Біжи sequelize db:migrate

Запуск міграцій на виробництво

Очевидно, що ви не можете ssh на виробничий сервер і запускати міграцію руками. Використовуйте umzug , рамковий інструмент міграції агностиків для Node.JS для виконання очікуваних міграцій до запуску програми.

Ви можете отримати список очікуваних / ще не виконаних міграцій, як це:

umzug.pending().then(function (migrations) {
  // "migrations" will be an Array with the names of
  // pending migrations.
}); 

Потім виконайте міграцію ( всередині зворотного дзвінка ). Метод Execute - це функція загального призначення, яка виконує для кожної заданої міграції відповідну функцію:

umzug.execute({
  migrations: ['some-id', 'some-other-id'],
  method: 'up'
}).then(function (migrations) {
  // "migrations" will be an Array of all executed/reverted migrations.
});

І я пропоную зробити це до запуску програми і намагається обслуговувати маршрути кожен раз. Щось на зразок цього:

umzug.pending().then(function(migrations) {
    // "migrations" will be an Array with the names of
    // pending migrations.
    umzug.execute({
        migrations: migrations,
        method: 'up'
    }).then(function(migrations) {
        // "migrations" will be an Array of all executed/reverted migrations.
        // start the server
        app.listen(3000);
        // do your stuff
    });
});

Я зараз не можу спробувати це, але на перший погляд це має спрацювати.

UPD квітня 2016

Через рік, як і раніше корисно, тому ділюся своїми поточними порадами. Наразі я встановлюю sequelize-cliпакунок як необхідну живу залежність, а потім змінюю сценарії запуску NPM package.jsonтаким чином:

...
"scripts": {
  "dev": "grunt && sequelize db:migrate && sequelize db:seed:all && node bin/www",
  "start": "sequelize db:migrate && sequelize db:seed:all && node bin/www"
},
...

Єдине, що мені потрібно зробити на виробничому сервері - це npm start. Ця команда запустить усі міграції, застосує всі сівалки та запустить сервер додатків. Не потрібно викликати umzug вручну.


3
Це звучить як те, що я шукаю. Це не здається настільки магічним і автоматичним, як "належить", але, можливо, це найкраще, на що можна сподіватися. Однак зараз я не працюю з Sequelize і не зможу перевірити це найближчим часом. Але якщо хтось інший погодиться, що це рішення добре, я прийму цю відповідь. Я все ще вважаю трохи сумним, що, мабуть, немає можливості автоматично зробити ці міграції з відмінностей між версіями моделі.
тремтіння

4
@tremby Єдиною рамкою, яку я використав, яка справді розуміє моделі, було Django. Він аналізує моделі і запитує на кшталт "Ну, здається, ви перейменували ім'я поля на ім'я-ім'я в" Користувач моделі ". Чи хотіли б ви створити для цього міграцію?" У Django це працює майже магічно, інші інструменти, якими я користувався, припускають той самий підхід до міграцій, про який я згадував вище: ви відповідаєте за те, щоб писати міграції самостійно, глибоко розуміючи, яке поле того типу потрібно додати, щоб бути актуальним для ваших поточних станів моделі
f1nn

2
Можна позбутися pendingі тоді, executeі просто робити umzug.up().then(function (migrations) { app.listen(3000); }). Відповідно до документації umzug, це виконає всі очікувані міграції.
Винай

Після завершення міграції, як правило, додавати поля до схеми в оригінальний файл моделі?
theptrk

@ f1nn У мене є питання щодо вашої настройки, як ви керуєте кластеризацією додатків та доступністю? Я інтегрую pm2 у свій робочий процес, і, можливо, він не працює прямо з сценаріями npm.
діосней

17

Просто я це навчився сам, але, думаю, я б рекомендував зараз використовувати міграцію, щоб ви звикли до них. Я знайшов найкраще, щоб зрозуміти, що відбувається в міграції, - подивитися на sql на створених таблицях, sequelize.sync()а потім побудувати міграції звідти.

migrations -c [migration name] 

Створить файл міграції шаблонів у каталозі міграцій. Потім ви можете заповнити його потрібними полями. Цей файл повинен містити createdAt/ updatedAt, поля, необхідні для асоціацій тощо.

Для початкового створення таблиці вниз повинно бути:

migration.dropTable('MyTable');

Але наступні оновлення структури таблиці можуть залишити це поза та просто використовувати таблицю alter.

./node_modules/.bin/sequelize --migrate

Приклад створення виглядає так:

module.exports = {
  up: function(migration, DataTypes, done) {
    migration.createTable(
        'MyTable',
        {
          id: {
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true
          },
          bigString: {type: DataTypes.TEXT, allowNull: false},
          MyOtherTableId: DataTypes.INTEGER,
          createdAt: {
            type: DataTypes.DATE
          },
          updatedAt: {
            type: DataTypes.DATE
          }
        });
    done();
  },
  down: function(migration, DataTypes, done) {
    migration.dropTable('MyTable');
    done();
  }

Щоб повторити з початку:

./node_modules/.bin/sequelize --migrate --undo
./node_modules/.bin/sequelize --migrate

Я використовую каву для запуску насінного файла, щоб заповнити таблиці після:

coffee server/seed.coffee

Це просто функція створення в ньому, яка виглядає приблизно так:

user = db.User.create
  username: 'bob'
  password: 'suruncle'
  email: 'bob@bob.com'
.success (user) ->
  console.log 'added user'
  user_id = user.id
  myTable = [
    field1: 'womp'
    field2: 'rat'

    subModel: [
      field1: 'womp'
     ,
      field1: 'rat'
    ]
  ]

Не забудьте вивести свій sync()показник з індексу у своїх моделях, інакше це перезапише, що роблять міграції та насіння.

Документи можна знайти на веб-сторінці http://sequelize.readthedocs.org/en/latest/docs/migrations/ . Але основна відповідь - ви повинні додати все в собі, щоб вказати потрібні поля. Це не робить для вас.


5
Я не запитував, як створити та запустити міграцію - як ви вказали, це все доступно в документації. Мене просили - як їх використовувати в контексті багаторазового застосування, коли існуючі екземпляри потрібно оновити до нової версії бази даних, а для нових екземплярів потрібна база даних, зроблена з нуля. Або , можливо , ви будете відповідати , що і говорити , що я не повинен використовувати синхронізацію () на всіх, і робите початкову базу даних і всі зміни до нього в міграції. Це те, що ти кажеш?
тремтіння

1
@tremby Я думаю, що це те, що він говорить. Можна або використовувати синхронізацію та мати справу з результатами, або ви можете створити міграції всі вручну. Наші рамки в режимі Rails-esque генерують файли міграції на основі схеми різниці, я б ЛЮБИТЬ, якщо Sequelize зробить це для мене. Занадто багато болю робити міграції вручну ...
mpowered

Прикро, що тоді ви не sequelize.sync()можете створити створений скрипт, який створює всі базові таблиці та індекси як вашу першу міграцію (схожу з рейками) schema.rb. як sql, а потім введіть це у велику execзаяву під час першої міграції. Потім ви працюєте з поступовими змінами щодо відомої вихідної точки "версії 1.0".
thom_nic

11

Для розробки зараз є можливість синхронізувати поточні таблиці шляхом зміни їх структури. Використовуючи останню версію від sequelize github repo , тепер можна запустити синхронізацію з alterпараметром.

Table.sync({alter: true})

Застереження від документів:

Змінює таблиці відповідно до моделей. Не рекомендується для виробничого використання. Видаляє дані в стовпцях, які були видалені або змінили їх тип у моделі.


3

Зараз з новою секелізацією міграція дуже проста.

Це приклад того, що ви можете зробити.

    'use strict';

    var Promise = require('bluebird'),
        fs = require('fs');

    module.exports = {
        up: function (queryInterface, Sequelize) {

            return Promise
                .resolve()
                .then(function() {
                    return fs.readFileSync(__dirname + '/../initial-db.sql', 'utf-8');
                })
                .then(function (initialSchema) {
                    return queryInterface.sequelize.query(initialSchema);
                })
        },

        down: function (queryInterface, Sequelize) {
            return Promise
                .resolve()
                .then(function() {
                    return fs.readFileSync(__dirname + '/../drop-initial-db.sql', 'utf-8');
                })
                .then(function (dropSql) {
                    return queryInterface.sequelize.query(dropSql);
                });
        }
    };

Пам'ятайте, що вам потрібно встановити:

"dialectOptions": { "multipleStatements": true }

на конфігурацію бази даних


Це не просто скидає та відновлює базу даних?
ДВІЧІ

Я думаю, що використання початкового великого файлу sql не є рекомендованим способом зробити це, оскільки він прив’яже адаптер і базу даних, які в іншому випадку будуть агностичними базами даних, оскільки ви можете використовувати для розробки sqlite і для виробництва mariadb або іншого.
діосней

2

Використовуйте версію. Версія програми залежить від версії бази даних. Якщо нова версія вимагає оновлення бази даних, створіть для неї міграцію.

оновлення: я вирішив відмовитися від міграції ( KISS ) та запустити сценарій update_db (sync forse: false), коли це потрібно.


Аналогічно моїй відповіді на відповідь user1916988, ви говорите, що я взагалі не повинен користуватися sync(), і що мені потрібно вручну записати міграції зі схеми моделей старої версії на новіші версії?
тремтіння

Я поставив +1 видання через ваше оновлення. Я насправді думаю про те, щоб зробити те саме. Писати всі міграції вручну, коли програма може зробити це трохи дурно, тож я просто збираюся зробити сценарій вручну, який запускає додаток один раз і виконує функцію синхронізації.
Саллар

2

Трохи запізнюючись, і після прочитання документації вам не потрібно проводити ту першу міграцію, про яку ви говорите. Все, що вам потрібно зробити - це зателефонувати sync, щоб створити таблиці.

sequelize.sync()

Ви також можете запустити просту синхронізацію моделі, виконавши щось на кшталт:

Project.sync()але я думаю, що sequelize.sync()це корисніший загальний випадок для вашого проекту (доки ви імпортуєте хороші моделі в момент запуску).

(взято з http://sequelizejs.com/docs/latest/models#database-synchronization )

Це створить усі початкові структури. Після цього вам доведеться створювати міграції лише для того, щоб розвивати свої схеми.

сподіваюся, що це допомагає.


7
Я не думаю, що ви прочитали оригінальний пост дуже ретельно, або, можливо, я був недостатньо зрозумілий. Я більш ніж усвідомлюю sequelize.sync()і що це робить.
тремті

2

Sequelize може запускати довільний SQL асинхронно .

Що я б робив:

  • Створити міграцію (використовувати як першу міграцію);
  • Вивантажте свою базу даних, щось на зразок: mysql_dump -uUSER -pPASS DBNAME > FILE.SQL
  • Або вставити повний дамп як текст (небезпечний) або завантажити файл з повним дампам у Вузол:
    • var baseSQL = "LOTS OF SQL and it's EVIL because you gotta put \ backslashes before line breakes and \"quotes\" and/or sum" + " one string for each line, or everything will break";
    • var baseSQL = fs.readFileSync('../seed/baseDump.sql');
  • Запустіть цей дамп на Sequelize Migration:
module.exports = {
  up: function (migration, DataTypes) {
    var baseSQL = "whatever" // I recommend loading a file
    migration.migrator.sequelize.query(baseSQL);
  }
}

Це повинно подбати про налаштування бази даних, хоча проблема асинхронізації може стати проблемою. Якщо це трапиться, я upроздивився би спосіб відкласти повернення функції секвелювання до тих пір, поки queryфункція асинхронізації не буде закінчена.

Більше про mysql_dump: http://dev.mysql.com/doc/refman/5.1/uk/mysqldump.html
Докладніше про Sequelize Migrations: http://sequelize.readthedocs.org/en/latest/docs/migrations/
Більше про Запуск SQL зсередини Sequelize Migration: https://github.com/sequelize/sequelize/isissue/313


1

Ось мій поточний робочий процес. Я відкритий для пропозицій.

  1. Встановіть sequelize для створення таблиць, які не існують
  2. Встановіть sequelize для скидання та відновлення всіх таблиць у порожній базі даних під назвою _blank
  3. Використовуйте інструмент mysql для порівняння змін _blank та синхронізації змін за допомогою цього інструменту. Ще шукаю доступний інструмент, який може це зробити на mac. MySql Workbench виглядає так, що ви можете імпортувати модель з існуючої схеми, а потім синхронізувати схему. Спробуйте розібратися, як це зробити за допомогою командного рядка, щоб зробити це просто.

Таким чином, вам не доведеться вручну оновлювати таблицю міграцій і турбуватися про жирні пальці, але ви все одно отримаєте ORM.


1

Друже, у мене було те саме запитання і мені вдалося зрозуміти, як ними користуватися.

Я почав без секелізації ORM, тому в мене вже була модель даних.
Мені довелося автоматично генерувати моделі за допомогою sequelize-auto і генерувати їх міграції за допомогою цього файлу, який ви створюєте https://gist.github.com/ahelord/a7a7d293695b71aadf04157f0f7dee64 і ставите синхронізувати ( {Force: false})
Це в розробці. модель та міграції та виконувати їх щоразу, коли я тягну код.

У виробництві сервер знаходиться лише вгорі, тому вам потрібно буде запускати лише міграції, і в кожному команді керування виконуватимуть версію моделі, не зупиняючи бекенд


1

Я переглянув цю посаду та подібні запитання, вона не дуже відповіла на мене. Міграція корисна для розкручування локальних баз даних та для оновлення даних у виробництві

Я поставив це запитання тут і відповів на нього: Робочий процес для обробки секвелізованих міграцій та ініціалізації?

Версія TL-DR для проекту Greenfield

  1. Створіть схему вашої бази даних, як звичайно, використовуючи чисті сценарії SQL або використовуючи інструмент gui
  2. Коли ви доопрацюєте всі свої 95% схеми db і ви задоволені нею, продовжте і перемістіть її до послідовності, перемістивши весь .sqlфайл на
  3. Зробіть свою першу міграцію. Запустіть sequelize init:migrateу будь-якій папці, де ви modelsперебуваєте
  4. Створіть свій перший файл міграції. Біжиsequelize migration:generate --name [name_of_your_migration]
  5. У цьому файлі міграції помістіть цей код туди
("use strict");
/**
 * DROP SCHEMA public CASCADE; CREATE SCHEMA public
 * ^ there's a schema file with all the tables in there. it drops all of that, recreates
 */
const fs = require("fs");
const initialSqlScript = fs.readFileSync("./migrations/sql/Production001.sql", {
  encoding: "utf-8",
});
const db = require("../models");
module.exports = {
  up: () => db.sequelize.query(initialSqlScript),
  down: () =>
    db.sequelize.query(`DROP SCHEMA public CASCADE; CREATE SCHEMA public;
`),
};

введіть тут опис зображення

із цією загальною структурою папок

введіть тут опис зображення

  1. Тепер ваша налаштування секвелювання синхронізована з вашою початковою схемою бази даних
  2. коли ви хочете відредагувати схему бази даних, запустіть її ще раз sequelize migration:generate --name [name_of_your_migration]
  3. Вперед і внесіть свої зміни тут на шляху upта downміграції. Це ваші заяви ALTER для зміни назв стовпців, DELETE, ADD Стовпців тощо
  4. Біжи sequelize db:migrate
  5. Ви хочете, щоб моделі синхронізувались із змінами вашого віддаленого db, так що зараз ви можете зробити npm install sequelize-auto.
  6. Це прочитає поточну схему бази даних у вашій базі даних та автоматично генерує файли моделей. Скористайтеся командою, подібною до цієї, sequelize-auto -o "./models" -d sequelize_auto_test -h localhost -u my_username -p 5432 -x my_password -e postgresзнайденої під https://github.com/sequelize/sequelize-auto

Ви можете використовувати git для перегляду дифлогів на вашій моделі, у моделі бази даних повинні бути лише зміни, що відображають зміни. Як бічна примітка, ніколи не змінюйте modelsбезпосередньо, якщо ви використовуєте sequelize auto, оскільки це створить їх для вас. Крім того, вам більше не слід змінювати схему бази даних безпосередньо за допомогою файлів SQL, надано це варіант, оскільки ви також можете імпортувати ці .sqlфайли

Тепер схема вашої бази даних оновлена, і ви офіційно перейшли до секвелювання лише міграцій баз даних.

Все контролюється версіями. Це ідеальний робочий процес для розробників баз даних та бекенду


0

Є ще більш простий спосіб (уникати Sequalize). Що йде так:

  1. Ви вводите команду всередині свого проекту: npm run migrate: new

  2. Це створює 3 файли. Файл js та два файли sql, названі вгору та вниз

  3. Ви поміщаєте свій оператор SQL у ті файли, що є чистою sql
  4. Потім ви вводите: npm run migrate: up або npm run migrate: down

Щоб це не працювало, перегляньте модуль db-migrate .

Після того, як ви налаштуєте його (що не складно), змінити вашу БД дійсно легко і економить багато часу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.