I am trying to update with association using sequelize.js.
I have tried give example on stackoverflow namely the following links:
Sequelize update with association
Sequelize update with association
Updating attributes in associated models using Sequelize
all of these links did not get me to the goal i am trying to accomplish.
My model is as follow, I have a country module and a city module. a country has many cities. please refer to the module bellow.
Please advise.
country.js file
module.exports = function (sequelize, DataTypes) {
var country= sequelize.define('COUNTRY', {
COUNTRY_ID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
COUNTRY_NAME: DataTypes.STRING,
COUNTRY_CURRENCY: DataTypes.STRING
}, {
freezeTableName: true,
classMethods: {
associate: function (models) {
COUNTRY_ID.hasMany(models.CITIES, {
foreignKey: 'COUNTRY_ID'
})
}
},
instanceMethods: {
updateAssociation: function (onSuccess, onError) {
country.findAll({
where: {
COUNTRY_ID: req.params.country_id
},
include: [
{
model: sequelize.import('./cities.js'),
}
]
})
})
.then(country =>{
const updatePromises = country.map(countries =>{
return countries.updateAttributes(req.body);
});
const updatePromisescities = list.CITY.map(cities =>{
return cities.updateAttributes(req.body.CITYs[0]);
});
return sequelize.Promise.all([updatePromises, updatePromisescities ])
}).then(onSuccess).error(onError);
}
}
});
return country;
};
city.js file
module.exports = function (sequelize, DataTypes) {
var CITY = sequelize.define('LIST_CODE', {
CITY_ID: {
type: DataTypes.INTEGER,
primaryKey: true
},
COUNTRY_ID: {
type: DataTypes.INTEGER,
primaryKey: true
}
}, {
freezeTableName: true,
timestamps: false,
classMethods: {
associate: function (models) {
// associations can be defined here
CITY.belongsTo(models.COUNTRY, {
foreignKey: 'COUNTRY_ID'
})
}
}
});
return CITY;
};
Related
I have two tables medforms and category each medform can have multiple categories. for multiple categories, I made another association table medform_categories.
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class MedForm 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) {
// define association here
}
};
MedForm.init({
med_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
med_name: {
type: DataTypes.STRING,
allowNull: false
},
}, {
sequelize,
modelName: 'medforms',
});
MedForm.associate = function (models) {
MedForm.hasMany(models.medforms_category, {
foreignKey: 'med_id',
as: 'medform'
});
};
return MedForm;
};
category table schema:
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Category extends Model {
static associate(models) {
}
};
Category.init({
category_id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
category_name: {
type: DataTypes.STRING,
},
}, {
sequelize,
modelName: 'categories',
});
Category.associate = function (models) {
Category.hasMany(models.medforms_category, {
foreignKey: 'category_id',
as: 'category'
});
};
return Category;
};
and finally the association table medform_category
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Medform_categories extends Model {
static associate(models) {
}
};
Medform_categories.init({
medform_category_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
category_id: {
type: DataTypes.INTEGER,
references: {
model: 'categories',
key: 'category_id'
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
med_id: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'medforms',
key: 'med_id'
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE'
},
}, {
sequelize,
modelName: 'medform_categories',
});
Medform_categories.associate = function (models) {
Medform_categories.belongsTo(models.medforms, {
foreignKey: 'med_id',
as: 'medform'
});
Medform_categories.belongsTo(models.categories, {
foreignKey: 'category_id',
as: 'category'
});
};
return Medform_categories;
};
now I want data like:
"category": [
{
"category_id": 1,
"category_name": "cat1",
"medforms": {
"med_id": 1,
"med_name": "Mobilfunk 1",
"med_fullname": "Mobilfunk 1",
},
{
"med_id": 2,
"med_name": "Mobilfunk 2",
"med_fullname": "Mobilfunk 2",
}
},
{
"category_id": 2,
"category_name": "cat2",
"medforms": {
"med_id": 1,
"med_name": "Mobilfunk 1",
"med_fullname": "Mobilfunk 1",
},
{
"med_id": 3,
"med_name": "Mobilfunk 3",
"med_fullname": "Mobilfunk 3",
}
},
]
can some one please help me here? what I should do here? Inside the
controller to fetch data like mentioned above?
const db = require("../models");
const Categories = db.categories; // tables db instance
// Retrieve all objects (with include)
exports.getAllCategories = (req, res) => {
Categories.findAll({
include: [
{
model: db.medforms_category,
as: 'category',
include: [
{
model: db.medforms,
as: 'medform',
}]
},
],
})
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving all data."
});
});
};
If you have a N:N relation, you not necessarely need to have a Model to represent this table.
// Medforms
// ...
static associate(models) {
this.belongsToMany(models.categories, { through: 'medform_categories' });
}
// Categories
// ...
static associate(models) {
this.belongsToMany(models.medforms, { through: 'medform_categories' });
}
// Query will be something like
const categories = await Categories.findAll({
where: {...},
include: ['medforms']
})
const medforms = await Medforms.findAll({
where: {...},
include: ['categories']
})
I am using sequelize for the first time and I having trouble getting my head around the association / foreign key relationships when pulling data into my jsons. I have some experience with SQL joins when I used PHP and I want to display the values that relate to the integer values in my diveSchool model.
Is there an easy way to do this without creating a complicated API?
The integers with ID relate to other tables and I have the foreign keys already created in pgadmin. Obviously the integers will mean nothing by themselves when displayed on the front-end.
module.exports = (sequelize, Sequelize) => {
const diveSchool = sequelize.define("diveSchools", {
diveSchoolID: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
diveSchoolName: {
type: Sequelize.TEXT
},
diveSchoolLocation: {
type: Sequelize.TEXT
},
diveSchoolRegionID: {
type: Sequelize.INTEGER
},
diveCertificatesOfferedID: {
type: Sequelize.INTEGER
},
diveSpotsOfferedID: {
type: Sequelize.INTEGER
},
diveSchoolGeo: {
type: Sequelize.GEOMETRY('POINT'),
allowNull: false
},
},
{
timestamps: false
}, {});
diveSchool.associate = function(models){
diveSchool.belongsTo(models.diveRegion, {foreignKey: 'diveSchoolRegionID', as: 'diveRegion'})
diveSchool.belongsTo(models.diveCertification, {foreignKey: 'diveCertification', as: 'diveCertification'})
diveSchool.belongsTo(models.diveSpot, {foreignKey: 'diveSpotID', as: 'diveSpot'})
};
return diveSchool;
};
diveRegion.js
module.exports = (sequelize, Sequelize) => {
const diveRegion = sequelize.define("diveRegions", {
diveRegionID: {
type: Sequelize.INTEGER,
primaryKey: true
},
diveRegion: {
type: Sequelize.TEXT
}},
{
timestamps: false
},{});
diveRegion.associate = function(models){
diveRegion.hasMany(models.diveSchool, {as: 'diveRegion'})
};
return diveRegion;
};
diveCertifications.js
module.exports = (sequelize, Sequelize) => {
const diveCertification = sequelize.define("diveCertifications", {
diveCertificationID: {
type: Sequelize.INTEGER,
primaryKey: true
},
diveCertificationName: {
type: Sequelize.TEXT
}},
{
timestamps: false
},{});
diveCertification.associate = function(models){
diveCertification.hasMany(models.diveSchool, {as: 'diveCertificatesOfferedID'})
diveCertification.hasMany(models.diveCertsCompleted, {as: 'diveCertsCompletedID'})
};
return diveCertification;
};
diveSchool.controller.js API
exports.allDiveSchools = (req, res) => {
approvedDivingSchool.findAll({})
.then((approvedDivingSchool) => {
const diveSchoolsList = [];
for (i = 0; i < approvedDivingSchool.length; i++) {
diveSchoolsList.push(approvedDivingSchool[i].dataValues);
}
if (!approvedDivingSchool) {
return res.status(404).send({ message: "No dive schools stored in this region." });
}
res.status(200).send({
data: diveSchoolsList,
});
})
.catch((err) => {
res.status(500).send({ message: err.message });
});
};
Check out eager loading and how to code associations in the Sequelize docs. Note that I already had associations in the style above in model that didn't work however there are are examples of how to code include statements with the "example1.belongsTo(example2) style and then the include statements inside the 'where' methods in API's.
https://sequelize.org/master/manual/eager-loading.html
I have three tables (all associated model classnames use PascalCase)
schools school_codes course
------ ------ ------
id (pk) code (pk) name
name school_id (fk) school_code (fk)
I'm trying to define sequelize relations, so that this Course lookup returns the associated School:
const courseWithSchool = await models.Course.findOne({
include: [{
model: models.School,
required: true,
}],
})
The mysql for this is very simple.
mysql> select c.*, s.* from courses c inner join school_codes sc on c.school_code = sc.code inner join schools s on s.id = sc.school_id;
How do I define the relations in sequelize models (without modifying existing schema)? Thanks!
Here are the model definitions I have:
schools.js
module.exports = (sequelize, DataTypes) => {
const School = sequelize.define('School', {
name: DataTypes.STRING,
}, { underscored: true, freezeTableName: true, tableName: 'schools' })
return School
}
course.js
module.exports = (sequelize, DataTypes) => {
const Course = sequelize.define('Course', {
id: {
type: DataTypes.STRING,
primaryKey: true,
},
name: DataTypes.STRING,
school_code: {
type: DataTypes.STRING,
references: {
model: 'school_codes',
key: 'code',
}
}
}, { underscored: true, freezeTableName: true, tableName: 'courses' })
return Course
}
schoolcode.js
module.exports = (sequelize, DataTypes) => {
const SchoolCode = sequelize.define('SchoolCode', {
code:{
type: DataTypes.STRING,
primaryKey: true,
references: {
model: 'courses',
key: 'school_code'
}
},
school_id: {
type: DataTypes.INTEGER,
references: {
model: 'schools',
key: 'id',
},
},
}, { underscored: true, freezeTableName: true, tableName: 'school_codes', })
return SchoolCode
}
I'm just looking for the relations to add to the bottom of each model definition - example...
// School.associate = function (models) {
// School.belongsToMany(models.Course, {
// through: 'school_codes',
// foreignKey: 'school_id',
// otherKey: 'code'
// })
// }
We can keep association in its respective model. I prefer to keep association in respective master table rather than mapping table. The idea is to associate source model to target model and its relationship in both direction. For example let us say source model School has one SchoolCode target model and its reverse relation
//school.model.js
module.exports = (sequelize, DataTypes) => {
const School = sequelize.define('school', {
name: DataTypes.STRING,
}, { underscored: true, freezeTableName: true, tableName: 'schools' })
School.associate = function ({SchoolCode, Course}) {
School.hasOne(SchoolCode, {
foreignKey: 'school_id',
})
SchoolCode.belongsTo(School, {foreignKey: 'school_id'})
School.belongsToMany(Course, { through: SchoolCode , foreignKey : 'school_id'}); //added new
}
return School;
}
//course.model.js
module.exports = (sequelize, DataTypes) => {
const Course = sequelize.define('course', {
id: {
type: DataTypes.STRING,
primaryKey: true,
},
name: DataTypes.STRING,
school_code: {
type: DataTypes.STRING,
references: {
model: 'school_codes',
key: 'code',
}
}
}, { underscored: true, freezeTableName: true, tableName: 'courses' })
Course.associate = function ({SchoolCode, School}) {
Course.hasMany(SchoolCode, {
foreignKey: 'code',
})
Course.belongsToMany(School, { through: SchoolCode, foreignKey : 'code'}); //added new
}
return Course;
}
Finally the third model of SchoolCode (Mapping table).
Note that we don't have to add a reference school_code. It is a primaryKey code of same table. We use references mainly to define the foreign keys, no need for reverse definition here.
Hence commented that part from code below.
module.exports = (sequelize, DataTypes) => {
const SchoolCode = sequelize.define('SchoolCode', {
code:{
type: DataTypes.STRING,
primaryKey: true,
// references: {
// model: 'courses',
// key: 'school_code'
// }
},
school_id: {
type: DataTypes.INTEGER,
references: {
model: 'school',
key: 'id',
},
},
}, { underscored: true, freezeTableName: true, tableName: 'school_codes', })
return SchoolCode
}
References : https://sequelize.org/master/manual/assocs.html
You can define relations like
SchoolCode.belongsTo(School, { foreignKey: 'school_id', targetKey: 'id' });
Course.belongsTo(SchoolCode, { foreignKey: 'school_code', targetKey: 'code' });
I have simple sequelize models like below.
// user.js
module.exports = function(sequelize, DataTypes) {
const user = sequelize.define(
"User",
{
name: {
field: "name",
type: DataTypes.STRING(50),
unique: true,
allowNull: false
},
uid: {
field: "uid",
type: DataTypes.STRING(50),
allowNull: false
}
},
{
freezeTableName: true,
tableName: "user"
}
);
user.associate = function(models) {
user.hasMany(models.friend, {
foreignKey: "uid"
});
};
return user;
};
And there is another model.
// friend.js
module.exports = function(sequelize, DataTypes) {
const friend = sequelize.define(
"Friend",
{
uid: {
field: "uid",
type: DataTypes.STRING(50),
allowNull: false
},
jsonId: {
field: "json-id",
type: DataTypes.STRING(50),
allowNull: true
},
nlpId: {
field: "nlp-id",
type: DataTypes.STRING(50),
allowNull: true
}
},
{
freezeTableName: true,
tableName: "friend"
}
);
friend.associate = function(models) {
friend.belongsTo(models.user, { foreignKey: "uid" });
};
return friend;
};
And there is index.js. When I run sequelize, it gives me an error like "Error: Friend.belongsTo called with something that's not a subclass of Sequelize.Model".
Could you recommend some advice for this problem? Thank you so much for reading it.
db.user = require('./user')(sequelize, Sequelize);
db.friend = require('./friend')(sequelize, Sequelize);
Write to the user model
User.associate = models => {
User.hasMany(models.Friend, {
as: 'friends',
foreignKey: 'userId'
});
};
Write to the friend model
Friend.associate = models => {
Friend.belongsTo(models.User, {
as: 'friend',
foreignKey: 'userId'
});
};
I am trying to create one to many foreign key constraint between two tables. A client can have many environments.
Here is my snippet in the model.
Client.associate = function(models) {
Client.hasMany(models.Enviornment, {as: 'enviornments', foreignKey: 'clientId'})
};
The solution is here.
The client has many environments. (one to many association )
Here is a code snippet for a model client.
module.exports = (sequelize, DataTypes) => {
let client = sequelize.define ('client', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, field: 'id' },
...
}, {
associate: models => {
client.hasMany (models.enviornment, {
foreignKey: { name: 'client_id', allowNull: false }
});
},
});
return client;
};
Here is a code snippet for a model enviornment.
module.exports = (sequelize, DataTypes) => {
let enviornment = sequelize.define ('enviornment', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, field: 'id' },
...
}, {
associate: models => {
enviornment.belongsTo (models.client, {
foreignKey: { name: 'client_id', allowNull: false }
});
},
});
return enviornment;
};