Inheritance in sequelize model - node.js

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(...)

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.

How to define an association to a model with array of foreign keys using sequelize with postgres

I have two models using mongoose as shown below:
Teams
var mongoose = require('mongoose');
var teamsSchema = new mongoose.Schema({
Name: {
type: String,
required: true,
unique: true
},
Description: {
type: String
},
Is_Active: {
type: String,
enum: ["Y", "N"],
default: 'Y'
}
}, { timestamps: true });
module.exports = mongoose.model('teams', teamsSchema);
Users
var mongoose = require('mongoose');
var usersSchema = new mongoose.Schema({
First_Name: {
type: String
},
Last_Name: {
type: String
},
Email: {
type: String,
required: true,
unique: true
},
Teams: [{ type: mongoose.Schema.Types.ObjectId, ref: 'teams' }],
Is_Active: {
type: String,
enum: ["Y", "N"],
default: 'Y'
}
}, { timestamps: true });
module.exports = mongoose.model('users', usersSchema);
We would like to migrate from MongoDB to PostgreSQL and we are using sequelize and created models as below
Teams
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class teams extends Model {
static associate(models) {
// define association here
}
};
teams.init({
Name: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
Description: DataTypes.STRING,
Is_Active: {
type: DataTypes.ENUM,
values: ['Y', 'N'],
defaultValue: 'Y'
}
}, {
sequelize,
modelName: 'teams',
});
return teams;
};
Users
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class users extends Model {
static associate(models) {
// define association here
}
};
users.init({
First_Name: DataTypes.STRING,
Last_Name: DataTypes.STRING,
Email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
Teams: {
type: DataTypes.ARRAY(DataTypes.INTEGER)
},
Is_Active: {
type: DataTypes.ENUM,
values: ['Y', 'N'],
defaultValue: 'Y'
}
}, {
sequelize,
modelName: 'users',
});
return users;
};
With mongoose, we could able to get the User details along with Teams and Teams along with Users. How to associate a model in sequelize with an array of keys? How to write queries(find/join) in Sequelize with an array of foreign keys.
Once this is resolved, we need to think of nested arrays.
Defining associations between models are very simple, as you can find it here.
I can see that you already have the associate method in each model.
You should add this in each method in order to have the correct associations:
Teams
this.belongsToMany(models.users, { through: 'TeamUsers' });
Users
this.belongsToMany(models.teams, { through: 'TeamUsers' });
Also, you don't need the Teams property in the Users model, since many-to-many associations exploit an external table in relational databases.
Here is an example of how to include users when querying for teams:
models.teams.find({
include: models.users
}).then(foundTeamsWithUsers => {
// Handle here your teams: use users to access the list of users related to each team
}).catch(handleErrorFunction);
You can find more examples about eager loading with 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;
}

Sequelize Model Relationships

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

Resources