Para este tipo de relación, veamos cómo se podrían relacionar las tablas Captain
y Ship
, donde definimos que un capitán puede tener un solo barco y un barco solo puede pertenecer a un capitán.
**const { Sequelize, DataTypes } = require("sequelize");**
**const sequelize = new Sequelize("your URI string", {...config});**
**const captainSchema = {
name: {
primaryKey: true,
allowNull: false,
unique: true,
type: DataTypes.STRING
}
};
const shipSchema = {
name: {
primaryKey: true,
allowNull: false,
unique: true,
type: DataTypes.STRING
},
captainName: {
field: "captain_name",
unique: true,
allowNull: false,
type: DataTypes.STRING,
references: {
model: "captains",
key: "name"
},
onUpdate: "CASCADE",
onDelete: "SET NULL"
}
};
const Captain = sequelize.define("Captain", captainSchema, {
tableName: "captains",
timestamps: false
});
const Ship = sequelize.define("Ship", shipSchema, {
tableName: "ships",
timestamps: false
});
sequelize.sync(); //también se podrían usar migraciones**
Con este código lo que hicimos fue definir dos esquemas para cada modelo, además como se puede notar en el schema de Ship
hay un campo muy importante que hace de llave foránea para permitir que podamos crear una asociación entre los dos modelos. Veamos cada propiedad de dicho campo con un poco más de detalle:
field
→ define que la columna para la llave foránea se va a llamar captain_name.unique
→ con esta regla declaramos que un mismo capitán puede tener un solo barco, por lo que la relación uno a uno funciona como debe.allowNull
→ indicamos que un barco no puede ser creado sin un capitán correspondiente.type
→ el tipo de dato que dicha columna va a almacenar.references
→ este objeto es el que hace que la magia ocurra, en su propiedad model
le decimos que la llave foránea va a apuntar hacia la tabla captains y con el campo key
le especificamos que apunta hacia el campo id de dicha tabla; mejor dicho, le indicamos que apunte hacia el campo id de la tabla captains.onUpdate
→ indicamos qué se debería hacer si el nombre del capitán cambia; en este caso indicamos que si el nombre del capitán cambia, entonces su referencia en la tabla ships también debería actualizarse.onDelete
→ indicamos qué se debería hacer si el nombre del capitán se elimina, mejor dicho, qué debería pasar cuando la tupla del capitán se elimine; en este caso le decimos que si la tupla del capitán se borra, entonces el valor de la referencia debería cambiar a null
.Ahora que ya tenemos los modelos definidos podemos asociarlos. Para realizar este tipo de asociación, Sequelize nos provee con dos métodos que funcionan de forma similar, las diferencias son muy mínimas.
sourceModel.hasOne(targetModel, {...options})
→ Representa una relación de uno a uno e indica que la foreign key (llave foránea) se debe establecer en el target model.
**Captain.hasOne(Ship, {
foreignKey: "captainName",
as: "ship",
});**
Este código le especifica a Sequelize que la llave foránea va a ser el campo captainName
del target model (Ship
) y además con la propiedad as
le agregamos un alias a dicha asociación, para que así podamos hacer peticiones con joins y demás más fácilmente. Con esto hecho ya tenemos una asociación entre los dos modelos.
sourceModel.belongsTo(targetModel, {...options})
→ Representa una relación de uno a uno e indica que la foreign key (llave foránea) se debe crear en el source model.
**Ship.belongsTo(Captain, {
foreignKey: "captainName",
as: "captain",
});**
Este código le especifica a Sequelize que la llave foránea va a ser el campo captainName
del source model (Ship
) y además con la propiedad as
le agregamos un alias a dicha asociación, para que así podamos hacer peticiones con joins y demás más fácilmente. Con esto hecho ya tenemos una asociación entre los dos modelos
Importante!!! En el campo de
foreignKey
, que se agrega al momento de establecer la asociación, se coloca el nombre de la propiedad que se declaró en el schema, no el valor que se define enfield
.
Al final, con cualquiera de los dos métodos el resultado es exactamente igual y no hay problema alguno, es un simple tema de gustos.
El campo/columna referenciado en la llave foránea debe ser único, de otra forma puede que obtengamos errores a la hora de ejecutar el código.