Além do npm init -y
para criar o projeto Node, teremos que instalar as dependências. Para essa tarefa específica, é necessário, vamos ter que instalar:
- O
sequelize
que irá permitir a manipulação do banco SQL pelo JavaScript, - O
mysql2
que é o drive do dialeto que iremos usar, e - O
sequelize-cli
, que permitirá administrarmos o banco de dados através de linhas de comandonpx
. Essa dependência é usada como dependência de desenvolvimento apenas.
Os arquivos de configuração contém as informações necessárias sobre senhas, endereços e locais necessários para que todas as conexões possam ser realizadas com sucesso. Ao menos dois arquivos de configuração serão necessários:
config/database.js
, é um objeto literal que contém as informações gerais de conexão do banco de dados, como o endereço do servidorhost
a portaport
o usuáriousername
e senhapassword
, o nome do bando de dadosdatabase
e o dialeto de SQLdialect
..sequelizerc
, é um objeto literal que contém ao menos a propriedadeconfig
, com o caminho do arquivoconfig/database.js
e o"migrations-path"
que é o caminho da pastamigrations
.
Esse arquivo tem o nome de index.js
e fica na raíz da pasta de banco de dados database
. Sempre que acionado o banco de dados, a seleção cairá diretamente nesse arquivo, que irá garantir que haja conexão e comunicação com o banco de dados.
Essa é a sintaxe básica do arquivo:
// carrega a classe Sequelize como dependência
const Sequelize = require('sequelize');
// Carrega os modelos que estão na pasta
const [nome do modelo] = require('../models/[arquivo do modelo]');
// Carrega as condigurações do banco
const [nome das configuracoes] = require('../config/database');
// Estabelece a conexão
const [nome da conexao] = new Sequelize([variavel de configuracoes]);
// Conecta cada modelo
[nome do modelo].init([nome da conexao]);
// exporta a conexão
module.exports = [nome da conexao];
Basta inserir: require([caminho da pasta de banco de dados])
no arquivo app.js
.
Ao rodar npx sequelize db:create
, será criado o banco de dados informado no arquivo de configuração.
- Inserir o caminho de
migrations-path
no.sequelizerc
- Criar a migration de criação das tabelas
- Criar o template com
npx sequelize migration:create --name=[nome da migration]
- Editar o template. A arrow function
up
edown
contém as instruções a serem realizadas em caso de sucesso ou fracasso da migration. No caso da criação de tabela, é corriqueiro que o sucesso seja a criação de uma tabela e, o fracasso, o contrário disso, ou seja: deletar a tabela.
- Criar o template com
Os callbacks das migrations recebem queryInterface
(responsável pelos comandos do SQL) e Sequelize
(que contém os tipos de variáveis). Antes de criar uma migração, verifique a necessidade de criar o relacionamento entre as tabelas no tópico 8.1, abaixo. A estritura é a seguinte:
async up (queryInterface, Sequelize) {
return queryInterface.createTable(
[nome da tabela],
{
[nome da coluna]: { [configuracoes]}
}
)
}
Um modelo é um objeto que representa, no lado do JavaScript, uma tabela do banco de dados SQL.
A classe que representará a tabela é criada na pasta models
. Cada arquivo que representará cada classe terá que importar, pelo menos, as classes Model
e DataTypes
da biblioteca sequelize
.
const { Model, DataTypes } = require('sequelize');
Logo após, criamos a classe extendendo a classe Model
. Essa classe deve, obrigatoriamente, implementar o médodo estático init()
, que receberá a conexão como argumento. Ess conexão tem o nome padrão de sequelize
.
class User extends Model {
static init (sequelize) {
// implementação
}
}
Esse método é proveniente da superclasse Model
e recebe dois objetos como argumento, um contendo as colunas como chave e o tipo de dados como valor. O segundo é a própria conexão, por padrão: sequelize
. No nosso exemplo:
class User extends Model {
static init (sequelize) {
super.init({
name: DataTypes.STRING,
}, {
sequelize
})
}
}
Para esses modelos recém criados funcionarem, devem ser importados no índice do banco de dados e seu método init evocado, usando como argumento a conexão.
// Importa o modelo
const User = require('../models/User');
// ...
// Evoca o método init recebendo a conexão
User.init(connection);
//
A criação dos relacionamentos é realizada tanto na parte do banco SQL, através das migrations, quanto nos modelos.
No processos detalhados no tópico 6.1, as colunas que representam chaves estrangeiras devem ser declaradas da seguinte forma:
async up (queryInterface, Sequelize) {
return queryInterface.createTable(
[nome da tabela],
// Demais colunas
{
[nome da coluna da chave estrangeira]: {
references: {
model: '[nome da tabela original]',
key: '[nome da coluna original]'
},
onDelete: '[acao a ser realizada se a chave original for deletada]',
onUpdate: '[acao a ser realizada se a chave original for atualizada]'
}
}
// Outras colunas
)
}
No código acima, temos o parâmetro references
que faz alusão ao comando SQL REFERENCES
, informando um objeto contendo as informações de qual é o nome da tabela model
e a coluna key
de onde vêm a chave estrangeira. Ainda, devem ser incluídas as informações de o que será feito se os valores originais da chave estrangeira forem alterados onUpdate
ou deletados onDelete
. Todas as opções a esse respeito podem ser consultadas na documentação do Sequelize, aqui.
Quando há tabelas que possuem relacionamentos, além do método init()
, é necessário implementar o método associate()
no processo descrito no tipico 7.1 acima. O método associate()
deverá ser implementado tanto na tabela que contém os valores originais quanto na tabela que conterá a chave estrangeira.
Na tabela original, recebe todos os modelos do banco como argumento (geralmente nomeado como models
) e sua implementação aponta qual a tabela que recebe a chave estrangeira models.[nome da tabela]
, além de um método de this
que especifica qual é o tipo de relacionamento que recebe um objeto contendo um objeto que contém, no mínimo qual é nome da coluna que recebe a chave estrangeira foreginKey
e qual será o nome que se dará para esse relacionamento as
. Esse nome de relacionamento será útil na hora de sua utilização.
class [nome da tabela] extends Model {
// Restante do código ...
static associate (models) {
this.[tipo de relacionamento](
models.[nome da tabela que tem a classe estrangeira],
{
foreignKey: 'categoryId',
as: '[nome do relacionamento]'
}
)
};
// Restante do código.
}
Já na tabela que recebe a chave estrangeira, o que muda é que deve ser informado o modelo referente à tabela que contém a chave original. Além disso, on nome do relacionamento deve ser diferente. Por exemplo, em um relacionamento entre uma tabela Categories
e Users
, podemos nomear o relacionamento em Categories
de members
, já que os usuários que usarão sua chave como estrangeira serão "os membros daquela categoria"; por sua vez, na tabela Users
, o nome do relacionamento pode ser member
, já que cada usuário é "membro daquela categoria".
Sobre o método que aponta qual é o tipo de relacionamento geralmente serão "tem um" .hasOne
ou "tem muitos" .hasMany
na tabela original e "pertence a um" .belongsTo
ou "pertence a muitos" belongsToMany
nas tabelas que conterão a chave estrangeira e cada combinação desses pares gerarão os muitos tipos de relacionamentos: um para um, um para muitos ou muitos para muitos.
Tabela original | Tabela que recebe a chave estrangeira | Relacionamento |
---|---|---|
hasOne |
belongsTo |
um para um |
hasMany |
belongsTo |
muitos para um |
hasOne |
belongsToMany |
um para muitos |
hasMany |
belongsToMany |
muitos para muitos |
A exemplo do que foi feito com o método init
dos modelos no tópico 7.2 acima, o método associate
também deve ser inicializado no banco de dados. Isso deve ser feito evocando o método no arquivo, mas passando apenas o objeto de modelos que está na conexão connection.models
ao invés de toda a conexão.
// Importa o modelo
const User = require('../models/User');
// ...
// Evoca o método init recebendo os modelos do objeto de conexão
User.associate(connection.models);
//
A forma mais tradicional de utilizar os relacionamentos através das associações é através dos métodos de consulta, como .findAll()
ou .findByPk()
. Nesse caso, deve-se passar um objeto com o parâmetro include
que, por sua vez, também trará um objeto com o parâmetro association
que terá como valor o nome da associação que se deseja invocar, assim:
.findAll({
include: {
association: '[nome da associação]'
}
})
Concluído ✅
- Acesse esta pasta pelo repositório local, em seu computador
- Preencha os dados referentes ao acesso de seu banco de dados no arquivo
config/database.js
, sobretudo usuário e senha. - Instale as dependências com
npm i
- Crie o banco com
npx sequelize db:create
e as migrações comnpx sequelize db:migrate
- Inicie o projeto com
node app.js
ounodemon app.js