Sequelize association cant work on my code,please - mysql

im recently to sequelize.
I have 2 table, data_track and car_detail. i want to try associate that 2 table but it never associated.
it's always return error
SequelizeEagerLoadingError: car_detail is not associated to data_track!
please help me
both table have same primary key column name
data_track.js
const Sequelize = require('sequelize')
const gps_status_track = require("./../../configs/gps_status_track")
const data_track = gps_status_track.define('data_track',
{
car_id:{
type:Sequelize.INTEGER,
primaryKey:true
},
off_time:{
type:Sequelize.INTEGER,
},
nopol:{
type:Sequelize.STRING
},
wilayah:{
type:Sequelize.STRING
},
status:{
type:Sequelize.STRING
},
o_path:{
type:Sequelize.STRING
},
keterangan:{
type:Sequelize.STRING
},
last_update:{
type:"TIMESTAMP"
},
},
{
createdAt:'created_at',
updatedAt:'updated_at',
deletedAt:'deleted_at',
freezeTableName: true,
}
)
data_track.associate = (models)=>{
data_track.belongsTo(models.car_detail,{foreignKey:'car_id',as:'dataTrack'})
}
module.exports = data_track
car_detail.js
const Sequelize = require('sequelize')
const gps_status_track = require("./../../configs/gps_status_track")
const car_detail = gps_status_track.define('car_detail',
{
car_id:{
type:Sequelize.INTEGER,
primaryKey:true
},
nopol:{
type:Sequelize.STRING
},
wilayah:{
type:Sequelize.STRING
},
o_path:{
type:Sequelize.STRING
},
},
{
createdAt:'created_at',
updatedAt:'updated_at',
deletedAt:'deleted_at',
freezeTableName: true,
}
)
car_detail.associate = (models)=>{
car_detail.hasOne(models.data_track,{foreignKey:'car_id',as:'carDetail'})
}
module.exports = car_detail
Thanks!

Try doing it this way:
DataTrack.js:
module.exports = (sequelize, Sequelize) => {
const DataTrack = sequelize.define('data_track',
{
car_id: {
type: Sequelize.INTEGER,
primaryKey: true
},
off_time: {
type: Sequelize.INTEGER,
},
nopol: {
type: Sequelize.STRING
},
wilayah: {
type: Sequelize.STRING
},
status: {
type: Sequelize.STRING
},
o_path: {
type: Sequelize.STRING
},
keterangan: {
type: Sequelize.STRING
},
last_update: {
type: "TIMESTAMP"
},
},
{
createdAt: 'created_at',
updatedAt: 'updated_at',
deletedAt: 'deleted_at',
freezeTableName: true,
});
return DataTrack;
}
CarDetail.js:
module.exports = (sequelize, Sequelize) => {
const CarDetail = sequelize.define('car_detail',
{
car_id: {
type: Sequelize.INTEGER,
primaryKey: true
},
nopol: {
type: Sequelize.STRING
},
wilayah: {
type: Sequelize.STRING
},
o_path: {
type: Sequelize.STRING
},
},
{
createdAt: 'created_at',
updatedAt: 'updated_at',
deletedAt: 'deleted_at',
freezeTableName: true,
}
);
return CarDetail;
}
db.config.js:
const env = require('./env.js')
const Sequelize = require('sequelize')
const sequelize = new Sequelize(env.database, env.username, env.password, {
host: env.host,
dialect: env.dialect
})
const db = {}
db.Sequelize = Sequelize
db.sequelize = sequelize
db.data_track = require('../models/DataTrack')(sequelize, Sequelize)
db.car_detail = require('../models/CarDetail')(sequelize, Sequelize)
db.car_detail.hasOne(db.data_track, { foreignKey: { name: 'cars_id', allowNull: false } })
db.data_track.belongsTo(db.car_detail, { foreignKey: { name: 'cars_id', allowNull: false } })
module.exports = db

You're defining association is not correct.
car_detail.hasOne(models.data_track,{foreignKey:'carIDFK', sourceKey: 'cardDetailPKId', as:'carDetail'})
In the data track model, the association will look like.
data_track.belongsTo(models.car_detail,{foreignKey:'carIDFK', targetKey: 'cardDetailTablePKId'})

Related

Creating Associations with sequelize and mysql

I am trying to create seqeulize models in nodejs app on mysql db. However, When I run the codes, foreign keys are not being created as intended.
This are my models:
Category Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Category = sequelize.define("Category", {
category_id: {
type: DataTypes.STRING(255),
unique: true,
primaryKey: true,
},
name: { type: DataTypes.STRING, unique: true, allowNull: false },
slug: { type: DataTypes.STRING, unique: true, allowNull: false },
created_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal("CURRENT_TIMESTAMP"),
},
updated_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal(
"CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
),
},
});
Category.associate = (models) => {
Category.hasMany(models.Product);
};
return Category;
};
Product Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Product = sequelize.define("Product", {
product_id: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
slug: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
sku: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
short_description: {
type: DataTypes.TEXT,
allowNull: false,
},
description: {
type: DataTypes.TEXT,
allowNull: false,
},
price: {
type: DataTypes.DECIMAL,
allowNull: false,
min: 1,
},
discount: {
type: DataTypes.DECIMAL,
allowNull: true,
},
quantity: {
type: DataTypes.INTEGER,
},
vat: {
type: DataTypes.DECIMAL,
allowNull: true,
},
tags: {
type: DataTypes.STRING(255),
allowNull: true,
},
rate: {
type: DataTypes.INTEGER,
allowNull: true,
},
points: {
type: DataTypes.INTEGER,
allowNull: true,
},
new: {
type: DataTypes.VIRTUAL,
get() {
var msPerDay = 8.64e7;
// Copy dates so don't mess them up
var x0 = new Date(this.getDataValue("created_at"));
var x1 = new Date();
// Set to noon - avoid DST errors
x0.setHours(12, 0, 0);
x1.setHours(12, 0, 0);
// Round to remove daylight saving errors
return Math.round((x1 - x0) / msPerDay) <= 30;
},
set(value) {
throw new Error("Can't set Product.new property.");
},
},
thumb_image: {
type: DataTypes.STRING,
allowNull: true,
get() {
if (this.getDataValue("thumb_image")) {
return JSON.parse(this.getDataValue("thumb_image"));
}
return [];
},
set(val) {
this.setDataValue("thumbImage", JSON.stringify(val));
},
},
images: {
type: DataTypes.STRING,
allowNull: true,
get() {
if (this.getDataValue("images")) {
return JSON.parse(this.getDataValue("images"));
}
return [];
},
set(val) {
this.setDataValue("images", JSON.stringify(val));
},
},
featured: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
created_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal("CURRENT_TIMESTAMP"),
},
updated_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal(
"CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
),
},
});
Product.associate = (models) => {
Product.belongsTo(models.Category, {
foreignKey: "category_id",
});
Product.belongsTo(models.Brand, {
foreignKey: "brand_id",
});
Product.belongsTo(models.CartItem, {
foreignKey: "cart_id",
});
};
return Product;
};
Brand Model
"use strict";
module.exports = (sequelize, DataTypes) => {
const Brand = sequelize.define("Brand", {
brand_id: {
type: DataTypes.STRING(255),
unique: true,
primaryKey: true,
},
name: { type: DataTypes.STRING, unique: true, allowNull: false },
slug: { type: DataTypes.STRING, unique: true, allowNull: false },
created_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal("CURRENT_TIMESTAMP"),
},
updated_at: {
type: DataTypes.DATE,
defaultValue: sequelize.literal(
"CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
),
},
});
Brand.associate = (models) => {
Brand.hasMany(models.Product);
};
return Brand;
};
And these is my Models/index.js file
/* eslint-disable no-undef */
"use strict";
const fs = require("fs");
const path = require("path");
const Sequelize = require("sequelize");
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || "development";
const config = require(__dirname + "/../../config/config.js")[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
);
}
db.sequelize = sequelize;
db.Sequelize = Sequelize;
fs.readdirSync(__dirname)
.filter((file) => {
return (
file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
);
})
.forEach((file) => {
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes
);
db[model.name] = model;
});
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize
.sync({ force: process.env.NODE_ENV === "development" })
.then(() => {
console.log("Drop and re-sync db.");
});
module.exports = db;
Now when I run the server, I expected the products table to have the fields category_id and brand_id. However, am getting additional fields brand_brand_id and category_category_id on the products table.
Besides, I cannot retrieve the categories, brands and products with the include properties when fecthing data.
What I want is to have the products table properly created in the database with the required foreign keys
Since you have customized foreign keys you have to indicate them in both paired associations:
Category.associate = (models) => {
Category.hasMany(models.Product, { foreignKey: "category_id" });
};
Product.associate = (models) => {
Product.belongsTo(models.Category, {
foreignKey: "category_id",
});
Product.belongsTo(models.Brand, {
foreignKey: "brand_id",
});
Product.belongsTo(models.CartItem, {
foreignKey: "cart_id",
});
};
Brand.associate = (models) => {
Brand.hasMany(models.Product, { foreignKey: "brand_id" });
};

TypeError: models.leaves.getAllEmpoyees is not a function

I am writing a function in Schema Model for getting Data with a query. The query is working fine, but unfortunately i am getting an error regarding Function - getAllEmpoyees() not found. For Reference - my sequelize version is - 6.15.0 . I am new to Node.js. Can anyone help me out yrr, Thanks in Advance!
const Sequelize = require('sequelize');
module.exports = function(sequelize, DataTypes) {
return sequelize.define('leaves', {
id: {
autoIncrement: true,
type: DataTypes.BIGINT.UNSIGNED,
allowNull: false,
primaryKey: true
},
employee_id: {
type: DataTypes.INTEGER,
allowNull: false
},
leave_type_id: {
type: DataTypes.INTEGER,
allowNull: false
},
leave_reason: {
type: DataTypes.STRING(255),
allowNull: false
},
remark: {
type: DataTypes.STRING(255),
},
status: {
type: DataTypes.STRING(255),
allowNull: false
},
created_by: {
type: DataTypes.INTEGER
}
},
{
sequelize,
tableName: 'leaves',
timestamps: true,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "id" },
]
},
]
},
getAllEmpoyees = function() {
var query = "select * from leaves as l join leave_types as lt on l.leave_type_id=lt.id";
return sequelize.query(query, { type: sequelize.QueryTypes.SELECT});
},
);
};
const express = require('express');
const router = express.Router();
var path = require('path');
var root_path = path.dirname(require.main.filename);
var models = require(root_path + '/models');
var moment = require("moment");
router.get('/getallemployeeLeaves', (req, res) => {
console.log("All Fetched");
models.leaves.getAllEmpoyees().then(function (data) {
console.log("");
if (data.length > 0) {
res.json({
status: 200,
data: data
})
} else {
res.json({
status: 400,
})
}
})
})

sequelize - how to calculate the value of a column based on the value in other table

There are 2 tables which are users and tutorial.
The relationship:
users(1) : tutorial(Many)
The users table has below column
completeOneOfTheTutorial: {
type: DataTypes.BOOLEAN,
allowNull: false,
...
},
which is true when
isCompleted: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
is true in one of the tutorials.
If isCompleted is false for all tutorials of the same user, completeOneOfTheTutorial will be false
Example
User table
[
{
id: "user1",
completeOneOfTheTutorial: true
}
,
{
id: "user2",
completeOneOfTheTutorial: false
},
]
tutorial table
[
{
id: "tutorial1",
userId: "user1",
isCompleted: true
}
,
{
id: "tutorial2",
userId: "user1",
isCompleted: false
},
{
id: "tutorial1",
userId: "user2",
isCompleted: false
}
,
{
id: "tutorial2",
userId: "user2",
isCompleted: false
},
]
How should I modify this field in users.model.js
completeOneOfTheTutorial: {
type: DataTypes.BOOLEAN,
allowNull: false,
...
},
users.model.js
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const users = sequelizeClient.define('users', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
},
completeOneOfTheTutorial: {
type: DataTypes.BOOLEAN,
allowNull: false,
...
},
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
users.associate = function (models) {
users.hasMany(models.tutorial,{
foreignKey: 'userId'
});
};
return users;
};
tutorial.model.js
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const tutorial = sequelizeClient.define('tutorial', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4
},
isCompleted: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
tutorial.associate = function (models) {
tutorial.belongsTo(models.users);
};
return tutorial;
};

Sequelize - is it possible to limit the number of record in junction table

There are 3 tables student_teacher, student, teacher with below relationship.
Each teacher will be responsible for 5 students, so the relationship should be 1 to Many, but I decide to create a junction table for storing extra information for this relationship.
When I create a student_teacher record, the payload will be like this:
{
"studentId": "xxx",
"teacherId": "yyy",
"groupName": "Group A"
}
Let's say I have record below now in table student_teacher:
[
{
"studentId": "studentA",
"teacherId": "teacherA",
"groupName": "Group X"
},
{
"studentId": "studentB",
"teacherId": "teacherA",
"groupName": "Group X"
},
{
"studentId": "studentC",
"teacherId": "teacherA",
"groupName": "Group X"
},
{
"studentId": "studentD",
"teacherId": "teacherA",
"groupName": "Group X"
},
{
"studentId": "studentE",
"teacherId": "teacherA",
"groupName": "Group X"
}
]
There are already 5 record for teacherA in table student_teacher, I will to forbid to create 1 more record for teacherA.
Is it possible to do it in Sequelize? Or handle I need to handle it in node.js function?
student-teacher.model.js
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const studentTeacher = sequelizeClient.define('student_teacher', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
},
studentId: {
allowNull: false,
type: DataTypes.UUID,
references: { model: 'student', key: 'id' },
defaultValue: Sequelize.UUIDV4,
unique: 'studentId_foreign_idx'
},
teacherId: {
allowNull: false,
type: DataTypes.UUID,
references: { model: 'teacher', key: 'id' },
defaultValue: Sequelize.UUIDV4,
unique: 'teacherId_foreign_idx'
},
groupName: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: ''
},
...
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
studentTeacher.associate = function (models) {};
return studentTeacher;
};
student.model.js
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const student = sequelizeClient.define('student', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
},
email: {
type: DataTypes.STRING,
allowNull: false,
isEmail: true,
unique: 'email'
},
firstName:{
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
},
lastName:{
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
}
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
student.associate = function (models) {
student.belongsToMany(models.teacher, { as: 'teachers', through: 'student_teacher', foreignKey: 'studentId', onDelete: 'cascade' })
};
return student;
};
teacher.model.js
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const teacher = sequelizeClient.define('teacher', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
},
email: {
type: DataTypes.STRING,
allowNull: false,
}
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
teacher.associate = function (models) {
teacher.belongsToMany(models.student, { as: 'students', through: 'student_teacher', foreignKey: 'teacherId', onDelete: 'cascade' })
};
return teacher;
};
Sequelize's hooks are very compatible with your requirement:
// in your student-teacher.model.js model (before you return the model)
studentTeacher.beforeCreate(async (instance, options) => {
try {
const result = await studentTeacher.findAll({
where: {
teacherId: instance.teacherId
}
});
if(result.length === MAX_RECORDS_FOR_TEACHER) {
throw new Error(`Cannot create more instnaces for ${instance.teacherId}`);
}
}
catch(e) {
throw e; // You must throw an error inside the hook in order to cancel
// the real statement execution.
}
});
Read more: https://sequelize.org/master/manual/hooks.html

SequelizeEagerLoadingError: product is not associated to collection

I use sequelize ORM in Mysql. I have 3 Models: Product, Collection, CollectionProduct
relationship between Product and Collection are many to many and for handle this in sequelize i used belongsToMany association. every thing is Ok but when i run this code to get a collection with its products with include Eager this error occure:
SequelizeEagerLoadingError: product is not associated to collection!
Product Model:
module.exports = (sequelize, Sequelize) => {
const Product = sequelize.define('product', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
name_en: {
type: Sequelize.STRING(255),
},
description_en: {
type: Sequelize.STRING(1024),
},
price: {
type: Sequelize.FLOAT,
allowNull: false,
},
type: {
type: Sequelize.STRING(255),
},
height: {
type: Sequelize.INTEGER,
},
width: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {})
Product.associate = (models) => {
Product.belongsToMany(models.collection, { through: models.collectionProduct, as: 'collections', foreignKey: 'productId' })
}
return Product
}
Collection Model :
module.exports = (sequelize, Sequelize) => {
const Collection = sequelize.define(
'collection', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
allowNull: false,
autoIncrement: true,
},
name_en: {
type: Sequelize.STRING(255),
},
itemsCount: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {},
)
Collection.associate = (models) => {
Collection.belongsToMany(models.product, { through: models.collectionProduct, as: 'products', foreignKey: 'collectionId' })
}
return Collection
}
CollectionProduct Model:
module.exports = (sequelize, Sequelize) => {
const CollectionProduct = sequelize.define('collectionProduct', {
collectionId: {
type: Sequelize.INTEGER,
},
productId: {
type: Sequelize.INTEGER,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
allowNull: false,
},
}, {})
CollectionProduct.associate = (models) => {}
return CollectionProduct
}
routes/collection.js
const express = require('express')
const router = express.Router()
const Collection = require('../../controllers/collectionController')
router.get('/:id', async (req, res) => {
const { id: collectionId } = req.params
const collection = await Collection.getOne(collectionId)
return collection
}
collectionController
const db = require('../models/index')
const Collection = db.collection
const Product = db.product
const getOne = async (collectionId) => {
const collection = await Collection.findByPk(collectionId, {
include: {
model: Product,
as: 'products',
attributes: ['id', 'name_en'],
},
})
return collection
}
I found my problem. in collectionController i used model: Product
and Product should be a sequelize model. but in my code this is a function that have been called in models/index. so i changed my calling and pass a sequelize model to getOne