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.
Related
My sequelize migration file being referenced in terminal:
Sequelize CLI [Node: 16.10.0, CLI: 6.2.0, ORM: 6.7.0]
Loaded configuration file "db\config.js".
Using environment "development".
== 20211021030720-create-customers: migrating =======
ERROR: Cannot read properties of undefined (reading 'toString')
This is my model file:
const { Model, DataTypes, Sequelize } = require('sequelize');
const { USER_TABLE } = require('./user.model');
const CUSTOMER_TABLE = 'customers';
const CustomerSchema = {
costomerId: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER,
},
customerName: {
allowNull: false,
type: DataTypes.STRING,
},
customerLastname: {
allowNull: false,
type: DataTypes.STRING,
},
customerPhone: {
allowNull: true,
type: DataTypes.STRING,
},
createdAt: {
allowNull: false,
type: DataTypes.DATE,
field: 'create_at',
defaultValue: Sequelize.NOW,
},
userId: {
field: 'user_id',
allowNull: false,
type: DataTypes.INTEGER,
references: {
model: USER_TABLE,
key: 'userId'
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL'
}
}
class Customer extends Model {
static associate(models) {
this.belongsTo(models.User, {as: 'user'});
}
static config(sequelize) {
return {
sequelize,
tableName: CUSTOMER_TABLE,
modelName: 'Customer',
timestamps: false
}
}
}
module.exports = { CUSTOMER_TABLE, CustomerSchema, Customer };
Other posts mention that it can be caused by an invalid property of DataTypes but I have already checked the code several times and I cannot find the problem.
If other information to help solve, please ask for it.
EDIT
I realized that I wrote .addColumn instead .createTable. Now everything is working properly.
module.exports = {
up: async (queryInterface) => {
await queryInterface.createTable(CUSTOMER_TABLE, CustomerSchema);
},
everyone. I'm very new for sequelize ORM with nodejs.
I've just created couple files for models seperately and I also seperate sequelize.js to connect to database.
The problem is when I make association between model(file)(Self Associate work well) and I've got an error
**** "hasMany called with something that's not a subclass of Sequelize.Model"
I tried to solved this but doesn't work until I put every model in the same file. So, I realized that every model must use common sequelize connection.
Is there anyways to solve this problem without sequelize-cli (I don't want to use sequelize-cli)
My code belows
Many thanks,
sequelize.js
const config = require("config");
const { Sequelize } = require("sequelize");
const sequelize = new Sequelize(
config.get("database"),
config.get("user"),
config.get("cipher"),
{
dialect: "mariadb",
timezone: "Asia/Bangkok",
}
);
module.exports = sequelize;
user.js
const { DataTypes, Model } = require("sequelize");
const sequelize = require("./sequelize");
const Position = require("./position");
class User extends Model {}
User.init(
{
uuid: {
type: DataTypes.UUID,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
},
title: {
type: DataTypes.STRING,
allowNull: false,
},
firstname: {
type: DataTypes.STRING,
allowNull: false,
},
lastname: {
type: DataTypes.STRING,
allowNull: false,
},
phone: {
type: DataTypes.STRING,
allowNull: true,
},
email: {
type: DataTypes.STRING,
allowNull: true,
validate: {
isEmail: true,
},
},
imgurl: {
type: DataTypes.STRING,
allowNull: true,
},
login: {
type: DataTypes.STRING,
allowNull: false,
},
passphase: {
type: DataTypes.STRING,
allowNull: false,
},
status: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1,
},
},
{
sequelize,
modelName: "User",
tableName: "users",
timestamps: true,
}
);
User.belongsToMany(User, {
as: "CreatedUser",
foreignKey: "user_id",
through: "UserCreator",
});
User.belongsToMany(User, {
as: "Creator",
foreignKey: "creator_id",
through: "UserCreator",
});
User.belongsToMany(User, {
as: "ModifiedUser",
foreignKey: "user_id",
through: "UserModifier",
});
User.belongsToMany(User, {
as: "Modifier",
foreignKey: "modifier_id",
through: "UserModifier",
});
User.belongsTo(Position);
module.exports = User;
position.js
const { DataTypes, Model } = require("sequelize");
const sequelize = require("./sequelize");
const User = require("./user");
class Position extends Model {}
Position.init(
{
uuid: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
status: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1,
},
},
{
sequelize,
modelName: "Position",
tableName: "postions",
timestamps: true,
}
);
Position.hasMany(User, {
foreignKey: {
type: DataTypes.UUIDV4,
allowNull: false,
},
});
module.exports = Position;
Sequelize has a .define() method to create all your schemas in JSON. If you want to keep your connection to the database separate from your models, I suggest doing something like this
./models/schemas/User.js
const userSchema = {
attribute1: {
type: ...,
option1: ...,
option2: ...,
.
.
},
.
.
}
export default userSchema
Do the same with Position.js
Then:
./models/models.js
import {sequelize} from 'path/to/sequelize.js'
import positionSchema from './schemas/Position.js'
import userSchema from './schemas/User.js'
const User = sequelize.define("user", userSchema, { freezeTableName: true });
const Position = sequelize.define("position", positionSchema, { freezeTableName: true });
// add associations
export {
User,
Position,
.
.
}
I'm trying to run the following code block, for some reason the query tries to insert it into a column labeled "users->user_group"."userUuid", despite the fact that I have not reference the string literal userUuid once in the project (through search not in the code base), also check columns in pg-admin (using PostgreSQL), both columns in the user_group table are user_uuid and group_uuid, both columns are also validated and populated properly.
const result = await group.findAll({
include: user,
});
Postman body returns the following error
"hint": "Perhaps you meant to reference the column "users->user_group.user_uuid".",
I have 3 models user, group and user_group. The relations have been defined per documentation and countless other articles and videos.
user model
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define(
"user",
{
uuid: {
type: DataTypes.STRING,
primaryKey: true,
allowNull: false,
unique: true,
},
username: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
},
{
freezeTableName: true,
}
);
user.associate = (models) => {
user.belongsToMany(models.group, {
// as: "userUuid",
through: models.user_group,
foreignKey: "user_uuid",
});
};
return user;
};
group model
module.exports = (sequelize, DataTypes) => {
const group = sequelize.define(
"group",
{
uuid: {
type: DataTypes.STRING,
primaryKey: true,
allowNull: false,
unique: true,
},
title: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
},
},
{
freezeTableName: true,
}
);
group.associate = (models) => {
group.belongsToMany(models.user, {
// as: "groupUuid",
through: models.user_group,
foreignKey: "group_uuid",
});
};
return group;
};
user_group model
module.exports = (sequelize, DataTypes) => {
const user_group = sequelize.define(
"user_group",
{
uuid: {
type: DataTypes.STRING,
primaryKey: true,
allowNull: false,
unique: true,
},
user_uuid: {
type: DataTypes.STRING,
allowNull: false,
references: {
model: "user",
key: "uuid",
},
},
group_uuid: {
type: DataTypes.STRING,
allowNull: false,
references: {
model: "group",
key: "uuid",
},
},
author: {
type: DataTypes.STRING,
unique: true,
allowNull: true,
},
},
{
freezeTableName: true,
}
);
user_group.associate = (models) => {
user_group.belongsTo(models.user, {
foreignKey: "user_uuid",
});
user_group.belongsTo(models.group, {
foreignKey: "group_uuid",
});
};
return user_group;
};
Any help is much apprecaited, thanks!
You should indicate otherKey option along with foreignKey in belongsToMany in order to indicate a foreign key column on the other model otherwise you will end up with a default name of an other key, see below:
The name of the foreign key in the join table (representing the target model) or an object representing the type definition for the other column (see Sequelize.define for syntax). When using an object, you can add a name property to set the name of the column. Defaults to the name of target + primary key of target (your case: user+uuid)
group.belongsToMany(models.user, {
// as: "groupUuid",
through: models.user_group,
foreignKey: "group_uuid",
otherKey: "user_uuid"
});
const result = await group.findAll({
include: {user},
});
you should to create like this. baecause you missing this {}.
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;
}
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);