Retrieve sequelize rows through a many-to-many relationship table - node.js

I have two models Company and Contractor linked through a CompanyContractor relational table.
company.js
'use strict';
module.exports = (sequelize, DataTypes) => {
const Company = sequelize.define('Company', {
name: {
type: DataTypes.STRING(30),
allowNull: false,
unique: true
},
slug: {
type: DataTypes.STRING(30),
allowNull: false
},
description: DataTypes.STRING(200),
}, {});
Company.associate = function(models) {
Company.belongsToMany(models.Contractor, { through: 'CompanyContractor', as: 'contractors',foreignKey: 'companyId' });
};
return Company;
};
contractor.js
'use strict';
module.exports = (sequelize, DataTypes) => {
const Contractor = sequelize.define('Contractor', {
name: {
type: DataTypes.STRING(50),
allowNull: false
}
}, {});
Contractor.associate = function(models) {
Contractor.belongsToMany(models.Company, { through: 'CompanyContractor', as: 'contractors' });
};
return Contractor;
};
companyContractor.js
'use strict';
module.exports = (sequelize, DataTypes) => {
const CompanyContractor = sequelize.define('CompanyContractor', {
companyId: {
type: DataTypes.INTEGER,
allowNull: false
},
contractorId: {
type: DataTypes.INTEGER,
allowNull: false
}
}, {
timestamps: false
});
return CompanyContractor;
};
Is there a way to Contractor.findAll() through companyId?

Contractor.findAll({
include: [{
model: Company,
through: {
attributes: ['companyId']
}
}]
});
From the documentation

Related

Sequelize model field that I did not add

I have a user, role and their relation model, when I want to insert into the relation model I get this error:
error: column "userUserId" of relation "roles_users_relationships" does not exist.
Can you help with this error?
(sorry if I wrote something wrong, this is my first question on )
This is how my model looks
Role model:
const Schema = (sequelize, DataTypes) => {
const table = sequelize.define(
"roles", {
role_id: {
type: DataTypes.UUID,
defaultValue: sequelize.literal("uuid_generate_v4()"),
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
}
}, {
timestamps: false
}
);
table.associate = function (models) {
table.belongsToMany(models.users, {
through: "roles_users_relationship",
foreignKey: "role_id",
});
};
return table;
};
Users model:
const Schema = (sequelize, DataTypes) => {
const table = sequelize.define(
"users", {
user_id: {
type: DataTypes.UUID,
defaultValue: sequelize.literal("uuid_generate_v4()"),
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: true,
}
}, {
timestamps: false
}
);
table.associate = function (models) {
table.belongsTo(models.roles, {
through: "roles_users_relationship",
foreignKey: "user_id",
});
};
return table;
};
Roles Users relationship model:
const Schema = (sequelize, DataTypes) => {
const table = sequelize.define(
"roles_users_relationship", {
user_id: {
type: DataTypes.UUID,
allowNull: false,
},
role_id: {
type: DataTypes.UUID,
allowNull: false,
},
}, {
timestamps: false
}
);
return table;
};
In your through table you should add options in related table field:
references: {
model: User,
key: 'user_id'
}
Otherwise sequelize will do it automatically, like adding foreign key column in this way tableNamePrimaryKeyColumn in your case its 'userUserId'

How to use Sequelize belongsTo

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'
});
};

Create Association in Sequelize

I am using "sequelize": "^5.8.6" and have created my project structure using "sequelize-cli": "^5.4.0". I would like to create associations so that:
One company has many ratings
I have created a company model, which looks like that:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Company = sequelize.define('Company', {
name: DataTypes.STRING,
symbol: DataTypes.STRING,
}, {});
Company.associate = function(models) {
Company.hasMany(models.Rating);
};
return Company;
};
My Rating model looks like that:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Rating = sequelize.define('Rating', {
action: DataTypes.STRING,
}, {});
Rating.associate = function(models) {
Rating.belongsTo(models.Company);
// associations can be defined here
};
return Rating;
};
My Company Migration look like the following:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Companies', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
symbol: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Companies');
}
};
My Rating migration looks like the following:
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Ratings', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
companyid: {
type: Sequelize.INTEGER,
references: {
model: 'Company',
key: 'id',
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL',
},
action: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Ratings');
}
};
When running, I get the following error:
> npx sequelize-cli db:migrate
ERROR: Can't create table `test_db`.`ratings` (errno: 150 "Foreign key constraint is incorrectly formed")
Any suggestions what I am doing wrong?
I appreciate your replies!
If you haven't just left it out of your code, your company model association should read:
Company.associate = function(models) {
Company.hasMany(models.Rating, {
foreignKey: 'companyid',
targetKey: 'id'
});
};
And your rating model should read:
Rating.associate = function(models) {
Rating.belongsTo(models.Company, {
// associations can be defined here
foreignKey: 'companyid',
targetKey: 'id'
});
};

Update with association using Sequelize.js

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;
};

Node Sequelize migrations/models is it possible to share the same code?

I'm new at Sequelize so be patient.
I started up a new project using Sequelize
and migrations so I've got like this:
migrations/20150210104840-create-my-user.js:
"use strict";
module.exports = {
up: function(migration, DataTypes, done) {
migration.createTable("MyUsers", {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
first_name: {
type: DataTypes.STRING
},
last_name: {
type: DataTypes.STRING
},
bio: {
type: DataTypes.TEXT
},
createdAt: {
allowNull: false,
type: DataTypes.DATE
},
updatedAt: {
allowNull: false,
type: DataTypes.DATE
}
}).done(done);
},
down: function(migration, DataTypes, done) {
migration.dropTable("MyUsers").done(done);
}
};
models/myuser.js:
"use strict";
module.exports = function(sequelize, DataTypes) {
var MyUser = sequelize.define("MyUser", {
first_name: DataTypes.STRING,
last_name: DataTypes.STRING,
bio: DataTypes.TEXT
}, {
classMethods: {
associate: function(models) {
// associations can be defined here
}
}
});
return MyUser;
};
as you can see the table definition
is both on the migration and the model file.
I'm wondering if there is a way to share
the code ?
I mean I don't like to have logic in two files
if a field change I've to update twice.
UPDATE
following the Yan Foto example below
a different way may be cleaner.
schemas/users
'use strict';
module.exports = {
name: 'users',
definition : function(DataTypes) {
return {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
firstname: {
type:DataTypes.STRING
},
lastname: {
type:DataTypes.STRING
},
email: {
type: DataTypes.STRING,
unique: true
},
username: {
type:DataTypes.STRING,
unique: true
}
};
}
};
models/users
'use strict';
var Schema = require('../schemas/users');
module.exports = function(sequelize, DataTypes) {
return sequelize.define(
Schema.name,
Schema.definition(DataTypes),
{
freezeTableName: true ,
instanceMethods: {
countTasks: function() {
// how to implement this method ?
}
}
}
);
};
migrations/20150720184716-users.js
'use strict';
var Schema = require('../schemas/users');
module.exports = {
up: function (queryInterface, Sequelize) {
return queryInterface.createTable(
Schema.name,
Schema.definition(Sequelize)
);
},
down: function (queryInterface, Sequelize) {
return queryInterface.dropTable(Schema.name);
}
};
I wondered the same thing as I started using sequelize and here is my solution. I define my models as bellow:
module.exports = {
def: function(DataTypes) {
return {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
username: DataTypes.STRING,
password: DataTypes.STRING,
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE,
}
},
config: {}
};
Where def defines the attributes and config is the optional options object accepted by define or migration methods. And I import them using the following code:
fs.readdirSync(__dirname + '/PATH/TO/models')
.filter(function(file) {
return (file.indexOf('.') !== 0) && (file !== basename);
})
.forEach(function(file) {
var name = file.substring(0, file.lastIndexOf(".")),
definition = require(path.join(__dirname + '/models', file));
sequelize['import'](name, function(sequelize, DataTypes) {
return sequelize.define(
name,
definition.def(DataTypes),
definition.config
);
});
});
For the migrations I have a similar approach:
const path = require('path');
module.exports = {
up: function (queryInterface, Sequelize) {
return queryInterface.createTable(
'users',
require(path.join(__dirname + '/PATH/TO/models', 'user.js')).def(Sequelize)
);
},
down: function (queryInterface, Sequelize) {
return queryInterface.dropTable('users');
}
};

Resources