UPDATE
someone below suggested adding in a model id for shoutouts and I'm no longer getting the error, but now nothing is being saved to my database?
adding in the new information below:
I have a one to many relationship between users and shoutouts. Both models have email property,
I am trying to use a magic method to setup the shoutout. When I use user.createShoutout()
I can generate the shoutout, but the email property doesn't show up in the database.
const Sequelize = require('sequelize')
const db = require('../db')
const Shoutout = db.define('shoutout', {
//NEW
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
}, //OLD
name: {
type: Sequelize.STRING,
validate: {
notEmpty: true
},
email: {
type: Sequelize.STRING,
unique: true,
allowNull: false
}
},
message: {
type: Sequelize.TEXT,
allowNull: false
},
from: {
type: Sequelize.STRING
}
})
module.exports = Shoutout
associations:
User.hasMany(Shoutouts)
Shoutouts.belongsTo(User)
User.hasMany(Emails)
Emails.belongsTo(User)
when I use user.AddShoutout()
as follows:
let paramsObj = {
name: addEmail.firstName,
email:addEmail.email,
message: 'test msg',
userId: 3
}
//NEW
let id = 1;
const addInfo = await userThree.addShoutout(id,paramsObj)
//NEW
not getting the object error anymore, in fact not seeing any errors. But when I look in my shoutouts table nothing is getting added.
when I console.log addInfo
The user who tried to create the shoutout gets returned?
I need help with trying to get this user model magic method to generate a new shoutout!
Thanks for reading this, and any advice!
Your email field is nested within name field
const Sequelize = require('sequelize')
const db = require('../db')
const Shoutout = db.define('shoutout', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
}, //OLD
name: {
type: Sequelize.STRING,
validate: {
notEmpty: true
},
email: { # <----------------------------- nested too deep
type: Sequelize.STRING,
unique: true,
allowNull: false
}
},
message: {
type: Sequelize.TEXT,
allowNull: false
},
from: {
type: Sequelize.STRING
}
})
module.exports = Shoutout
Related
I have three tables companies, subscriptions and companySubscription. As name defined company can canbuy/have plan or one subscription belongs to many companies.
So in model/schema I have defined as follows:
companies.js
const sequelize = require("../utils/database");
const bcrypt = require("bcrypt");
const { DataTypes, Model } = require("sequelize");
const subscription = require("./subscriptions");
const CompanySubscription = require("./companySubscription");
class companies extends Model {}
companies.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
contactNo: {
type: DataTypes.STRING,
allowNull: true,
},
companySize: {
type: DataTypes.INTEGER,
allowNull: true,
},
},
{ sequelize, modelName: "companies" }
);
subscription.belongsToMany(companies, { through: CompanySubscription });
module.exports = companies;
subscription.js
const sequelize = require("../utils/database");
const { DataTypes, Model } = require("sequelize");
class subscription extends Model {}
subscription.init(
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
subscriptionPlanType: {
type: DataTypes.ENUM,
values: ["Yearly", "Monthly"],
allowNull: false,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
memberCount: {
type: DataTypes.INTEGER,
allowNull: false,
},
amount: {
type: DataTypes.FLOAT,
allowNull: false,
},
},
{ sequelize, modelName: "subscription" }
);
module.exports = subscription;
companySubscription.js
const sequelize = require("../utils/database");
const companies = require("./companies");
const subscription = require("./subscriptions");
const { DataTypes, Model } = require("sequelize");
class CompanySubscription extends Model {}
CompanySubscription.init(
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false,
},
status: {
type: DataTypes.ENUM,
values: ["active", "inactive"],
},
subscriptionType: {
type: DataTypes.ENUM,
values: ["Yearly", "Monthly"],
},
subscriptionPlanStartDate: {
type: DataTypes.DATE,
},
subscriptionPlanEndDate: {
type: DataTypes.DATE,
},
paidStatus: {
type: DataTypes.ENUM,
values: ["paid", "unpaid"],
},
paidDate: {
type: DataTypes.DATE,
},
},
{ sequelize, modelName: "CompanySubscription" }
);
module.exports = CompanySubscription;
In controller file I am able to manage to insert the data. Below is the code:
const addBIlling = async (req, res) => {
const foundSubcscription = await subscription.create({
subscriptionPlanType: "Monthly",
name: "s1",
memberCount: 15,
amount: 50.55,
});
const foundCompany = await companies.create({
name: "company1",
email: "company1#gmail.com",
contactNo: "87964644",
companySize: 20,
});
const insertedData = await foundSubcscription.addCompany(foundCompany, {
through: {
status: "active",
paidStatus: "paid",
subscriptionType: "Monthly",
subscriptionPlanEndDate: moment().add(1, "months"),
paidDate: moment().add(1, "months"),
},
});
console.log("inserted data ", insertedData);
res.json({ data: insertedData });
};
Now I want to fetch the records from db as which company has bought which subscription plan!
i.e. company name, subscription plan and its active and paid status and plan's expiry date.
I tried below code:
const billingList = async (req, res) => {
const billingData = await CompanySubscription.findAll({
include: [{ model: companies }],
});
console.log("billing data ", billingData);
};
Above code is throwing error "companies is not associated to CompanySubscription!".
Where have I made a mistake?
Don't try to import models to each other's modules directly. Define model registration functions in each model module and use them all to register models in one place/module and for associations you can define associate function inside each registration function and call them after ALL your models are already registered. That way you won't have cyclic dependencies and all associations will be correct.
See my answer here to get an idea how to do it.
I'm actually trying to set a foreign key in my model "Batiment" that references the primary key of the model "Zone". I found the sequelize doc. and tried to use it but I got some errors that i couldn't fix. So here i am to ask for help...
module.exports = (sequelize, Sequelize) => {
const zone = require("../models/Zone.model.js");
var Batiment = sequelize.define("batiment", {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
nom: {
type: Sequelize.STRING
},
code_batiment: {
type: Sequelize.STRING,
unique: true
},
d_creation: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
},
d_modification: {
type: Sequelize.DATE
},
},
{
tableName: 'batiment',
createdAt: false,
updatedAt: false,
});
Batiment.associate = (models) => {
Batiment.belongsTo(zone, {foreignKey: 'ZoneID', as: 'ZoneID'});
};
return Batiment;
};
I also found some similar problems on the forum with solutions that i've tried to applicate but with no success.
If someone can explain me what am I doing wrong and what I can do to fix it, I would be very grateful.
I'm new to using Sequelize and for that I strictly follow the documentation here. It is written that we must use hasOne(), hasMany(), belongsTo() in order to add automatically the foreign keys. In my situation: I have a Category and a FAQ model, defined so:
Category.js
const { Sequelize } = require('sequelize');
const sequelize = require('../database/connection');
const Category = sequelize.define('Category', {
id: {
type: Sequelize.DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
categoryShop_id: {
type: Sequelize.DataTypes.UUID,
allowNull: true
},
name: {
type: Sequelize.DataTypes.STRING,
allowNull: false
},
active: {
type: Sequelize.DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
},
parent_id: {
type: Sequelize.DataTypes.INTEGER,
allowNull: true
}
});
Category.associate = (models) => {
Category.hasMany(models.faqs, {
onDelete:'CASCADE',
onUpdate:'CASCADE'
});
};
module.exports = Category;
Faq.js
const { Sequelize } = require('sequelize');
const sequelize = require('../database/connection');
const Faq = sequelize.define('Faq', {
id: {
type: Sequelize.DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true
},
question: {
type: Sequelize.DataTypes.TEXT,
allowNull: false
},
answer: {
type: Sequelize.DataTypes.TEXT,
allowNull: false
},
product_id: {
type: Sequelize.DataTypes.STRING,
allowNull: true
},
active: {
type: Sequelize.DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
}
});
Faq.associate = (models) => {
Faq.belongsTo(models.categories, {
foreignKey: {
name: 'category_id',
allowNull: true
}
});
};
module.exports = Faq;
The migrations run without any errors, but I don't see the added columns to the table. What is the reason for this?
Your confusing model and migration code. Your migrations are ok, but lack the right foreign key columns for your associations.
Your association code looks ok but it belongs in your model.
Look at https://sequelizeui.app/ for some example code.
My problem is that when I execute this code:
const task = await db.tasks.findByPk(1)
const user = await db.users.findByPk(4)
await user.setTasks(task)
This happens:
Executing (default): SELECT `tasks`.`id`, `tasks`.`start_date` FROM `tasks` AS `tasks` WHERE `tasks`.`id` = '1';
Executing (default): SELECT `id`, `name`, `surname`, `email`, `role` FROM `users` AS `users` WHERE `users`.`id` = '4';
Executing (default): SELECT `id`, `task_id`, `user_id` FROM `users_tasks` AS `users_tasks` WHERE `users_tasks`.`user_id` = 4;
Executing (default): DELETE FROM `users_tasks` WHERE `user_id` = 4 AND `task_id` IN (2)
Executing (default): INSERT INTO `users_tasks` (`id`,`task_id`,`user_id`) VALUES (NULL,1,4);
The user with id 4 had a previous association with a task with id 2. The issue is, I want to keep that association! It is perfectly fine for the purpose of my application for a user to be assigned to more tasks (and vice versa).
I would actually say that that's the normal desired behaviour of a many-to-many relationship... why is Sequelize deleting the row on users_tasks before adding a new one, and how can I prevent this from happening?
Here is my user model:
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('users', {
id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING(50),
allowNull: false
},
surname: {
type: DataTypes.STRING(50),
allowNull: false
},
email: {
type: DataTypes.STRING(256),
allowNull: false
},
}, {
tableName: 'users',
timestamps: false,
})
User.associate = function (models) {
User.belongsToMany(models.tasks, {through: 'users_tasks', foreignKey: 'user_id'})
}
return User
}
Here is my task model:
module.exports = function(sequelize, DataTypes) {
var Task = sequelize.define('tasks', {
id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
start_date: {
type: DataTypes.DATE,
allowNull: true,
},
}, {
tableName: 'tasks',
timestamps: false
})
Task.associate = function (models) {
Task.belongsToMany(models.users, {through: 'users_tasks', foreignKey: 'task_id'})
}
return Task
}
And here is my join table:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('users_tasks', {
id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
task_id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
references: {
model: 'tasks',
key: 'id'
}
},
user_id: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
references: {
model: 'users',
key: 'id'
}
}
}, {
tableName: 'users_tasks',
timestamps: false
})
}
Do I need to change something on the models definitions, or do I need to change something in the way I call setTasks? Or else, what do I need to do? Why is Sequelize enforcing this weird and unwanted behaviour of deleting previously existing associations?
I found out that I should be using add instead of set if I want to keep the preexisting relations.
So, the correct way of achieving the result I want is this:
const task = await db.tasks.findByPk(1)
const user = await db.users.findByPk(4)
await user.addTasks(task)
I have two n:m sequelize models as shown below
// Organization Model
module.exports = {
attributes: {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
required: true
},
},
associations: function() {
Organization.belongsToMany(Contact, {
through : OrganizationContact,
foreignKey: {
name: 'organizationId',
allowNull: false
}
});
}
};
// OrganizationContact Model
module.exports = {
attributes: {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
}
}
}
// Contact Model
module.exports = {
attributes: {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
firstname: {
type: Sequelize.STRING,
required: true
},
lastname: {
type: Sequelize.STRING,
required: false
},
},
associations: function() {
Contact.belongsToMany(Organization, {
through : OrganizationContact,
foreignKey: {
name: 'contactId',
allowNull: false
}
});
}
};
I am trying to insert a contact and attach it to an existing organization. My data looks like
{
"firstname" : "Mathew",
"lastname" : "Brown",
"organizationId" : 1 // Add the contact to an existing organization. I am missing something here.
}
Note : There can be multiple contacts attached to multiple organizations. An organization is created before a contact.
Based on this documentation, after saving the contact when I tried
Organization.addContact(contact);
I get an exception saying
Organization.addContact is not a function
The addContact method should be called on instance of Organization rather than on the model itself, just as you do in the example code.
Organization.create(organizationData).then(organization => {
organization.addContact(contact).then(() => {
// contact was added to previously created organization
});
});
You do not need the organizationId attribute in your contact create data. If you want to add new contact to the organization with id: 1, then you first need to return the organization instance and then perform the addContact method
Organization.findByPrimary(1).then(organization => {
organization.addContact(contact).then(() => {
// contact was added to organization with id = 1
});
});