Sequelize Model Relationships - node.js

I have 2 models and what I am trying to do is when a match is created, it will automatically create a match report. here is the code:
Match.js
const Sequelize = require('sequelize');
const db = require('../config/database');
const Match = db.define('matches',{
id: {
type: Sequelize.INTEGER(10).UNSIGNED,
autoIncrement: true,
primaryKey: true
},
type: {
type: Sequelize.STRING,
defaultValue: 'main' //match type either Main or Sub
},
game_grp: {
type: Sequelize.SMALLINT(6),
defaultValue: null // belongs to main match side bet.
},
sub_type: {
type: Sequelize.STRING,
defaultValue: null //values: (other = 1stBlood,F10k), (main = MatchWinner), (handicap = Match Handicap)
},
name: {
type: Sequelize.STRING,
defaultValue: null
},
league_id: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'League', //leagues has many matches
key: 'id'
}
},
},
);
Match.associate = models => {
Match.hasMany(models.MatchReport, {
foreignKey: 'id'
});
};
module.exports = Match;
MatchReport.js
const Sequelize = require('sequelize');
const db = require('../config/database');
const MatchReport = db.define('match_reports',
{
id: {
type: Sequelize.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
references: {
model: 'Match', //MatchReport's ID belongs to matches'
key: 'id'
}
},
league_id: {
type: Sequelize.INTEGER,
defaultValue: 0,
references: {
model: 'Match',
key: 'league_id'
}
},
name: {
type: Sequelize.STRING,
defaultValue: null
},
status: {
type: Sequelize.STRING,
defaultValue: null //ongoing,draw,cancelled,open
},
);
module.exports = MatchReport;
I'm new to node.js and sequelize.js model relationships so it's quite hard to understand some of the documentation's details.
Any ideas on how to deal with this? TYIA

First, you have a problem with MatchReport definition:
It needs to have its own id as PK and not as FQ.
MatchReport.league_id is referencing to Match.league_id, so if you'll point to a Match instance it's redundant, right? So, let's point to Match instance instead.
Define your MatchReport as follows:
const Sequelize = require('sequelize');
const db = require('../config/database');
const MatchReport = db.define('match_reports',
{
id: {
type: Sequelize.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
},
match_id: {
type: Sequelize.INTEGER(10).UNSIGNED,
references: {
model: 'Match',
key: 'id'
}
},
name: {
type: Sequelize.STRING,
defaultValue: null
},
status: {
type: Sequelize.STRING,
defaultValue: null //ongoing,draw,cancelled,open
},
);
module.exports = MatchReport;
Now, there are some options to create MatchReport instance when a Match is created.
1) Put the logic inside a function that creates a match.
async function createMatch(match) {
// match is the object you want to insert.
var newMatch = await Match.create(data);
var newMatchReport = await MatchReport.create({
match_id: newMatch.id,
name: ...,
status: ...., //
});
}
2) Use the include option of sequelize.
async function createMatch(match) {
// match is the object you want to insert.
var newMatch = await Match.create(data, {
include: [{ model: MatchReport}]
});
}
Pay attention to the following points as well:
1) When creating an instance of a model the whole instance returns and not only the data. The data itself could be found under dataValues object.
2) You need to apply the associations between the models as follows:
In your Match model:
let MatchReport = require('./MatchReport');
Match.hasOne(MatchReport);
In your MatchReport model:
let Match = require('./Match');
MatchReport.belongsTo(Match);

Related

how to write migrations to add foreignkey to already existing tables in sequelize

I have this already created two tables called User and Profile.
This is how my model for User looks like..
const Sequelize = require("sequelize");
const db = require("../db");
const User = db.define("User", {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: Sequelize.STRING,
allowNull: true,
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
validator: {
isEmail: true,
},
},
});
module.exports = User;
and model for Profile looks like..
const Sequelize = require("sequelize");
const User = require("./User");
const db = require("../db");
const Profile = db.define("Profile", {
image: {
type: Sequelize.STRING,
},
description: {
type: Sequelize.TEXT,
},
});
module.exports = Profile;
Now I want to define a one-to-one relationship between User and Profile such that user will recieve a profileId column.
so i am defining it like this
Profile.hasOne(User, {
foreignKey: {
allowNull: false,
},
});
User.belongsTo(Profile);
Now i am not able to figure out how to write migrations for the newly added foreign key
can anyone help me please..
Thanks.
I got the answer. for someone who is confused like me here is the answer
since the User table already exists, migrations for the foreignkey will look like this
module.exports = {
async up(queryInterface, Sequelize) {
return await queryInterface.addColumn("Users", "ProfileId", {
type: Sequelize.INTEGER,
references: {
model: "Profiles",
key: "id",
},
});
},
async down(queryInterface, Sequelize) {
return await queryInterface.removeColumn("Users", "ProfileId", {
type: Sequelize.INTEGER,
references: {
model: "Profiles",
key: "id",
},
});
},
};
the Users in addColumn and removeColumn is the name of the table in which foreignkey was added.
the ProfileId is the name for foreignkey which you would have specified in hasOne.
hope this helps..

The associations are not getting created by sequelize, sqlite and electron

I am working on an electron app and for the database, I am using sqlite3 along with sequelize. I want to establish a one-to-many relationship between two of the following models.
Item
Metric
Metrics can be liters/kilograms/units and an item can be measured in any of these metrics. So following is how I have declared the Item model.
const { Model, DataTypes } = require("sequelize");
const sequelize = require("../database/db");
const Metric = require("./metricModel");
class Item extends Model {}
Item.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
metricId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: "metrics",
key: "id",
},
},
available: {
type: DataTypes.FLOAT,
defaultValue: 0,
},
incoming: {
type: DataTypes.FLOAT,
defaultValue: 0,
},
},
{
sequelize,
tableName: "items",
freezeTableName: true,
}
);
Item.associate = (models) => {
Item.belongsTo(models.Metric, { foreignKey: "metricId" });
};
module.exports = Item;
And following is how I have declared the Metric
const { Model, DataTypes } = require("sequelize");
const sequelize = require("../database/db");
const Item = require("./itemModel");
class Metric extends Model {}
Metric.init(
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
description: {
type: DataTypes.STRING(10000),
},
},
{
sequelize,
tableName: 'metrics', freezeTableName: true
}
);
Metric.associate = function (models) {
Metric.hasMany(models.Item, { foreignKey: "metricId" });
};
module.exports = Metric;
But in the logs, I can't see any association getting created.
Also on making a select query on items. like below.
const items = await Item.findAll({include: [Metric]});
I get below error
My bad, there was a duplicate column in my items model and since during debugging the table named item was present beforehand, it was working fine. If you encounter this issue, make sure all your tables are declared properly.

one-to-many relationship with sequelize

I have 2 tables, users and users_signature where the signature takes several applications and I need to make a select according to the application.
Models:
user
const { INTEGER } = require('sequelize');
const Sequelize = require('sequelize');
const database = require('../../config/db');
const User_has_signature = require('./user_has_signature');
const Usuario = database.define('usuario', {
usu_id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
usu_rg: {
type: Sequelize.STRING,
},
},
{
freezeTableName: true,
createdAt: false,
updatedAt: false,
});
User.hasMany(User_has_signature, {as: 'user_has_signature'});
module.exports = User;
User_has_signature
const { INTEGER } = require('sequelize');
const Sequelize = require('sequelize');
const database = require('../../config/db');
const User_has_signature = database.define('user_has_signature', {
usu_has_signature_id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
user_usu_id: {
type: Sequelize.STRING,
},
signature_aplicativo_signature_aplicativo_id: {
type: Sequelize.STRING,
},
signature_type_signature_type_id: {
type: Sequelize.STRING,
},
},
{
freezeTableName: true,
createdAt: false,
updatedAt: false,
});
User_has_signature.associate = (models) => {
User_has_signature.belongsTo(models.User,
{ foreignKey: 'user_usu_id', as: 'users' });
};
module.exports = User_has_signature;
Controller
UserController
const User = require("../../model/user/user")
const User_has_signature = require("../../model/user/user_has_signature")
async index(req, res){
const user = await User.findAll({
include: [{
model: User_has_signature,
foreignKey: 'user_usu_id',
through: {
where: {signature_ttype_signature_type_id: 3}
}
}]
})
res.status(200).json(user)
return
}
The error that is returning to me in the terminal is: (node:15168)
UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError:
user_has_signature is associated to usuario using an alias. You must
use the 'as' keyword to specify the alias within your include
statement
I think you have to specify the alias you have given when writing your query :
include: [{
model: User_has_signature,
foreignKey: 'user_usu_id',
as : 'users'
through: {
where: {signature_ttype_signature_type_id: 3}
}]
Either way I'm using Sequelize more in Typescript, so I'm not sure of the syntax.
The way it handles One to Many relationship isn't the clearest I've seen (Like Symfony or Spring)

Inheritance in sequelize model

I have some fields that are very common. (CreatedBy, CreatedDate, LastUpdatedBy, LastUpdatedDate).
When I create a model, is there any way I can inherit these properties in my model?
I looked into the sequelize docs. But could not find anything relevant there.
Currently I am specifying these properties in each and every model I create:
const Sequelize = require('sequelize');
const conn = require('../common/mssql-connection');
const Member = conn.define('Member', {
id: {
type: Sequelize.INTEGER,
field: "Id",
autoIncrement: true,
primaryKey: true
},
name: {
type: Sequelize.STRING,
field: "Name"
},//Everything below this line is repetitive in other models. Inheritance would be useful here.
createdDate: {
type: Sequelize.DATE,
field: "CreatedDate"
},
createdBy: {
type: Sequelize.STRING,
field: "CreatedBy"
},
lastUpdatedDate: {
type: Sequelize.DATE,
field: "LastUpdatedDate"
},
lastUpdatedBy: {
type: Sequelize.STRING,
field: "LastUpdatedBy"
}
})
module.exports = Member;
I didn't manage to find a "standard" way either, but you can intercept the original define function of the Sequelize constructor, taking care of your default fields:
const originalDefine = Sequelize.prototype.define;
Sequelize.prototype.define = function(tableName,fields){
return originalDefine.call(this,tableName, {
createdBy: { type: Sequelize.DataTypes.STRING,defaultValue:"default 'createdBy' value!!!!" },
...fields
})
}
Then create your Sequelize instance..
const sequelize = new Sequelize(...)

Unrecognized datatype in Sequelize Model

I am trying to create an attribute called "provider" in my postgresql model and make its data type an Object (see code below). However, I am getting the error Error: Unrecognized datatype for attribute "segment.provider".
I'm assuming this error is happening because I haven't specified what the data type of the "provider" attribute actually is (ie: type: DataTypes.OBJECT). To my knowledge, there's nothing in the Sequelize docs that demonstrates this ask of mine. Any and all help would be most appreciated. Thanks!
module.exports = (sequelize, DataTypes) => {
const Segment = sequelize.define(
'segment',
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
provider: {
providerName: DataTypes.STRING,
externalId: DataTypes.STRING,
email: DataTypes.STRING,
privacyPolicy: DataTypes.STRING
}
},
{
freezeTableName: true,
tableName: 'segment'
}
);
return Segment;
}
Every field defined on a model(Table) is mapped into a column on the database.
That is what sequelize basically does.
Now, is there a field on a PostgreSQL database which is an object?
For what you are trying to do, you just need to use associations between tables.
Create a new model (Table) called provider:
And add the associations as follows in the example:
module.exports = (sequelize, DataTypes) => {
const Provider = sequelize.define(
'provider',
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
name: {
type: DataTypes.STRING
},
email: {
type: DataTypes.STRING
},
privacyPolicy: {
type: DataTypes.STRING
}
},
{
freezeTableName: true,
tableName: 'provider'
}
);
// Apply the accosiation:
Provider.hasMany /* or has one */ (Segment, {foreignKey: 'provider_id'});
return Provider;
}
And in your Segment model add a foreign key and a reference to Provider
module.exports = (sequelize, DataTypes) => {
const Segment = sequelize.define(
'segment',
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
provider_id: {
type: DataTypes.INTEGER,
references: {
model: 'provider',
key: 'id
}
}
},
{
freezeTableName: true,
tableName: 'segment'
}
);
// Apply the accosiation:
Segment.belongsTo(Provider, {foreignKey: 'id'});
return Segment;
}

Resources