I'm learning to use Sequelize, and I'm stumped. I have two models, User and Salon, with a N:M relationship between them, mediated by an auxiliary table, UsersSalons (So an user might manage many salons, for a franchise for example, or a salon may be managed by many employees)
When creating a new salon, my intention is to associate the logged in user to it. However, while I get to save the new salon in the database, it never gets to be associated to the user, returning this error:
ERROR PUT /salons Error: TypeError: salon.addUser is not a function
When Googling this, it appears that the common cause of this error is trying to apply the function to the whole model class instead of an instance of it, but this is not what is occurring here.
Here's the PUT /salons route:
router.put('/', checkLoggedIn, (req, res, next) => {
const user = User.findOne({ where: { id: req.user[0].id } })
.then(() =>
Salon.create({
name: req.body.name,
street: req.body.street,
number: req.body.number,
zipcode: req.body.zipcode,
town: req.body.town,
province: req.body.province,
addressComplements: req.body.addressComplements,
phoneNumber: req.body.phoneNumber,
})
)
.then((salon) => {
console.log(salon)
salon.addUser(user) //and here is where the error happens
})
.then((salon) => res.status(200).json(salon))
.catch((err) => next(new Error(err)))
})
Just in case, here are the User and Salon models, as well as how the UsersSalons table has been created:
'use strict'
const { Model } = require('sequelize')
module.exports = (sequelize, DataTypes) => {
class Salon extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
Salon.belongsToMany(models.User, {
through: 'UsersSalons',
as: 'salon',
foreignKey: 'salonId',
otherKey: 'userId',
})
}
}
Salon.init(
{
name: { type: DataTypes.STRING, allowNull: false, unique: true },
street: { type: DataTypes.STRING, allowNull: false },
number: { type: DataTypes.STRING, allowNull: false },
zipcode: { type: DataTypes.STRING, allowNull: false },
town: { type: DataTypes.STRING, allowNull: false },
province: { type: DataTypes.STRING, allowNull: false },
addressComplements: DataTypes.STRING,
phoneNumber: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
sequelize,
modelName: 'Salon',
}
)
return Salon
}
'use strict'
const { Model } = require('sequelize')
module.exports = (sequelize, DataTypes) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
User.belongsToMany(models.Salon, {
through: 'UsersSalons',
as: 'user',
foreignKey: 'userId',
otherKey: 'salonId',
})
}
}
User.init(
{
email: {
type: DataTypes.STRING,
validate: { isEmail: true },
allowNull: false,
unique: true,
},
firstName: { type: DataTypes.STRING, allowNull: false },
lastName: { type: DataTypes.STRING, allowNull: false },
isActive: { type: DataTypes.BOOLEAN, defaultValue: false },
password: { type: DataTypes.STRING },
confirmationCode: DataTypes.STRING,
},
{
sequelize,
modelName: 'User',
}
)
return User
}
'use strict'
module.exports = {
up: async (queryInterface, Sequelize) => {
return queryInterface.createTable('UsersSalons', {
createdAt: { allowNull: false, type: Sequelize.DATE },
updatedAt: { allowNull: false, type: Sequelize.DATE },
userId: { type: Sequelize.INTEGER, primaryKey: true },
salonId: { type: Sequelize.INTEGER, primaryKey: true },
})
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('UsersSalons')
},
}
EDIT: After trying out Anatoly's suggestion, there's still errors going on. Here's the updated code for the PUT /salons route and the output:
router.put('/', checkLoggedIn, (req, res, next) => {
const user = User.findOne({ where: { id: req.user[0].id } })
.then(() => {
return Salon.create({
name: req.body.name,
street: req.body.street,
number: req.body.number,
zipcode: req.body.zipcode,
town: req.body.town,
province: req.body.province,
addressComplements: req.body.addressComplements,
phoneNumber: req.body.phoneNumber,
})
})
.then((salon) => {
console.log(`salon output after creation: ${salon}`)
return salon.addUser(user)
})
.then((salon) => res.status(200).json(salon))
.catch((err) => next(new Error(err)))
})
Executing (default): SELECT "id", "email", "firstName", "lastName", "isActive", "password", "confirmationCode", "createdAt", "updatedAt" FROM "Users" AS "User" WHERE "User"."id" = 1;
Executing (default): SELECT "id", "email", "firstName", "lastName", "isActive", "password", "confirmationCode", "createdAt", "updatedAt" FROM "Users" AS "User" WHERE "User"."id" = 1;
Executing (default): INSERT INTO "Salons" ("id","name","street","number","zipcode","town","province","phoneNumber","createdAt","updatedAt") VALUES (DEFAULT,$1,$2,$3,$4,$5,$6,$7,$8,$9) RETURNING "id","name","street","number","zipcode","town","province","addressComplements","phoneNumber","createdAt","updatedAt";
salon output after creation: [object SequelizeInstance:Salon]
Executing (default): SELECT "createdAt", "updatedAt", "salonId", "userId" FROM "UsersSalons" AS "UsersSalons" WHERE "UsersSalons"."salonId" = 15 AND "UsersSalons"."userId" IN ('[object Promise]');
ERROR PUT /salons Error: SequelizeDatabaseError: invalid input syntax for integer: "[object Promise]"
at [project route]/routes/salons.routes.js:34:26
at processTicksAndRejections (internal/process/task_queues.js:93:5)
PUT /salons 500 860.025 ms - 39