Association is using wrong column - node.js

I am using my existing database which has no foreign keys created but I am able to join two tables using sql query but I am not able to join them in sequelize.
There are two models:
- User:
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
steamid: DataTypes.STRING,
name: DataTypes.STRING,
img: DataTypes.STRING,
tradelink: DataTypes.STRING,
ban_chat: DataTypes.INTEGER,
block_sms: DataTypes.INTEGER,
balance: DataTypes.INTEGER,
ref: DataTypes.STRING,
refcode: DataTypes.STRING,
ip_address: DataTypes.STRING
}, {
timestamps: false
});
User.associate = function(models) {
// associations can be defined here
User.hasMany(models.Order,{
foreignKey: 'steamid',
as: 'orders'
});
};
return User;
};
Order:
const customDataTypes = require('../../core').SequelizeTimestamp;
module.exports = (sequelize, DataTypes) => {
var Order = sequelize.define('Order', {
steamid: DataTypes.STRING,
item_name: DataTypes.STRING,
price: DataTypes.FLOAT,
type: DataTypes.STRING,
website: DataTypes.STRING,
amount: DataTypes.INTEGER,
status: DataTypes.INTEGER,
img: DataTypes.STRING,
send_attempts: DataTypes.INTEGER,
message: DataTypes.STRING,
date: customDataTypes.TIMESTAMP,
}, {
timestamps: false
});
Order.associate = function(models) {
// associations can be defined here
Order.belongsTo(models.User, {
foreignKey: 'steamid',
as: 'user'
})
};
return Order;
};
In my API i want to get user and his orders.
So in the controller i am doing:
user.findOne({
where: { steamid: req.params.steamId },
include: [{
model: order,
as: 'orders',
limit: 50
}],
})
So I expect to have user order array in the response but for some reason I get empty orders array.
Sequelize is doing these two queries:
SELECT `User`.`id`, `User`.`steamid`, `User`.`name`, `User`.`img`, `User`.`tradelink`, `User`.`ban_chat`, `User`.`block_sms`, `User`.`balance`, `User`.`ref`, `User`.`refcode`, `User`.`ip_address` FROM `Users` AS `User` WHERE `User`.`steamid` = '1234' LIMIT 1;
This is successfully finding the user but the second query is incorrect:
SELECT `id`, `steamid`, `item_name`, `price`, `type`, `website`, `amount`, `status`, `img`, `send_attempts`, `message`, `date` FROM `Orders` AS `Order` WHERE `Order`.`steamid` IN (1) LIMIT 50;
This part is incorrect "WHERE Order.steamid IN (1)"
It is looking for orders which steamid is = 1 which is user id (primary key) but it should be user steamid which is "1234"
What is wrong with my associations?

If steamid is not a primary you should`t be using "targetKey" and "sourceKey"?
https://sequelize.org/master/manual/associations.html
Order.belongsTo(models.User, {
foreignKey: 'steamid',
targetKey: 'steamid',
as: 'user'
})
Order.belongsTo(models.User, {
foreignKey: 'steamid',
sourceKey: 'steamid',
as: 'user'
})

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'

should I define one-to-many association for all relations in graphql and sequelize?

I wanna create a graphql server in NODEJS/KOA using graphql, sequelize with the Postgres database. I have a Postgres database with more than 19 tables and break all many to many relations to one-to-many.
for example here one of the table(Supplier) which has one-to-many relations with others.
ERD Diagram for Supplier table
I defined models like this for supplier and wants to define association for it too.
how can do this?
module.exports = (sequelize, DataTypes) => {
const Supplier = sequelize.define(
'supplier',
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: DataTypes.STRING,
email: DataTypes.STRING,
title: DataTypes.STRING,
description: DataTypes.STRING,
log_file_id: DataTypes.STRING,
type: DataTypes.INTEGER,
last_updated_on: DataTypes.TIMESTAMPTZ,
last_updated_by_id: DataTypes.INTEGER,
last_updated_by_text: DataTypes.STRING,
created_on: DataTypes.TIMESTAMPTZ,
created_by_id: DataTypes.INTEGER,
created_by_text: DataTypes.STRING,
password: DataTypes.STRING,
},
{
freezeTableName: true,
},
)
Supplier.associate = models => {
Supplier.hasMany(models.files, models.contact,models.contact_detail)
}
return Supplier
}
Supplier.associate = models => {
Supplier.hasOne(models.files, {as: "Files", foreignKey: "supplier_id"});
Supplier.hasOne(models.contact, {as: "Contacts", foreignKey: "supplier_id"});
Supplier.hasOne(models.contact_detail, {as: "ContactDetails", foreignKey: "supplier_id"})
}

Problem setting up Sequelize association - query with 'include' is failing

I'm new to Sequelize and trying to test if an n:m association I set up between two models, User and Podcast, is working. When I try to run this query, I get some kind of DB error that isn't specific about what's wrong:
User.findOne({
where: { id: id },
include: [{ model: Podcast }]
});
Does anyone know what I'm messing up? I suspect there's something wrong in how I've set up the association, like I'm referencing the names of tables slightly incorrectly, but the migration to create the association worked.
Here's my User.js model file:
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
photo: {
type: DataTypes.STRING
}
});
User.associate = function(models) {
// associations can be defined here
User.belongsToMany(models.Podcast, {
through: 'user_podcast'
});
};
return User;
};
And here's my Podcast.js file:
'use strict';
module.exports = (sequelize, DataTypes) => {
const Podcast = sequelize.define('Podcast', {
id: {
type: DataTypes.STRING,
primaryKey: true,
allowNull: false
},
title: {
type: DataTypes.STRING,
allowNull: false
},
thumbnail: {
type: DataTypes.STRING
},
website: {
type: DataTypes.STRING
}
});
Podcast.associate = function(models) {
// associations can be defined here
Podcast.belongsToMany(models.User, {
through: 'user_podcast'
});
};
return Podcast;
};
And here's the migration I ran to join the two tables:
'use strict';
module.exports = {
up: function(queryInterface, Sequelize) {
return queryInterface.createTable('user_podcast', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
references: {
model: 'Users',
key: 'id'
}
},
podcastId: {
type: Sequelize.STRING,
references: {
model: 'Podcasts',
key: 'id'
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('user_podcast');
}
};
And here's the project on Github for further reference:
https://github.com/olliebeannn/chatterpod
You don't need to create a migration for the M:N table. Now you have something wrong on your user_podcast model. If you are setting a M:N relation between to tables your primary key will be the combination between the foreign key from these two models. If you still want a single id primary key for your table, then you won't use belongsToMany instead use hasMany on user and podcast models pointing to a new model user_podcast.
As far as I see on your first query, it seems that you really need a M:N relation so you can define the model as you do with user and podcast like this:
module.exports = (sequelize, DataTypes) => {
const UserPodcast = sequelize.define('user_podcast', {
userId: {
// field: 'user_id', #Use 'field' attribute is you have to match a different format name on the db
type: DataTypes.INTEGER
},
podcastId: {
// field: 'podcast_id',
type: DataTypes.INTEGER
},
});
UserPodcast.associate = function(models) {
models.User.belongsToMany(models.Podcast, {
as: 'podcasts', //this is very important
through: { model: UserPodcast },
// foreignKey: 'user_id'
});
models.Podcast.belongsToMany(models.User, {
as: 'users',
through: { model: UserPodcast },
// foreignKey: 'podcast_id'
});
};
return UserPodcast;
};
I do prefer to have the belongsToMany associations on the save function where I define the join model, and you have to notice that I used as: attribute on the association. This is very important because this will help sequelize to know which association are you referring on the query.
User.findOne({
where: { id: id },
include: [{
model: Podcast,
as: 'podcasts' //here I use the previous alias
}]
});

Sequelize nested associations with 3 tables

I have a little problem with associations on query, I've nested assocations (4 tables, Users, A, B & C, Users hasOne A, A hasMany B and belongsTo Users, B belongsTo A and hasMany C and C belongsTo B).
When I do a findOne on Users, including my 3 other tables like that :
Models.User.findOne({
where: { id: req.user.id },
include:[{
model: Models.Candidate, // Candidate Associations (user.candidate) (Table A)
as: 'candidate',
include:[{
model: Models.Experience, // (Table B) Experiences Associations (user.candidate.experiences)
as: 'experiences',
include: [{
model: Models.Service,
as: 'service'
}
}] // Service Associations (Table C)
}]
}]
})
I correctly get the searched row but the problem is on the left outer join query of the third assocations (table C), the generated query is
LEFT OUTER JOIN `Services` AS `candidate->experiences->service` ON `candidate->experiences`.`id` = `candidate->experiences->service`.`id`
But I want to have this query :
LEFT OUTER JOIN `Services` AS `candidate->experiences->service` ON `candidate->experiences`.`service_id` = `candidate->experiences->service`.`id`
So how can I do that ?
I searched some help on google and other forum and websites but I didn't manage to find my answer since few weeks.
Thanks a lot for help that you'll provide me !
Edit :
Here is my models :
User :
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false
},
role: {
type: DataTypes.STRING
},
type: {
type: DataTypes.ENUM,
values: ['admin', 'candidate', 'es', 'demo'],
allowNull: false
}
});
User.associate = function (models) {
User.hasOne(models.Candidate, {
foreignKey: 'user_id',
as: 'candidate'
});
};
return User;
};
Candidate (A) :
'use strict';
module.exports = (sequelize, DataTypes) => {
const Candidate = sequelize.define('Candidate', {
user_id: {
type: DataTypes.INTEGER,
primaryKey: true
},
es_id: DataTypes.INTEGER,
description: DataTypes.TEXT,
photo: DataTypes.STRING,
video: DataTypes.STRING,
status: DataTypes.STRING,
note: DataTypes.STRING,
views: DataTypes.INTEGER
}, {});
Candidate.associate = (models) => {
Candidate.belongsTo(models.User, {
foreignKey: 'id',
onDelete: 'CASCADE'
});
Candidate.hasMany(models.Experience, {
foreignKey: 'candidate_id',
as: 'experiences'
});
};
return Candidate;
};
Experience (B) :
'use strict';
module.exports = (sequelize, DataTypes) => {
const Experience = sequelize.define('Experience', {
name: {
type: DataTypes.STRING,
allowNull: false
},
candidate_id: DataTypes.INTEGER,
poste_id: DataTypes.INTEGER,
service_id: DataTypes.INTEGER,
internship: DataTypes.BOOLEAN,
start: DataTypes.DATE,
end: DataTypes.DATE,
current: DataTypes.BOOLEAN
}, {});
Experience.associate = function (models) {
Experience.belongsTo(models.Candidate, {
foreignKey: 'id',
onDelete: 'CASCADE'
});
Experience.hasOne(models.Service, {
foreignKey: 'id',
targetKey: 'service_id',
as: 'service'
});
};
return Experience;
};
Service (C) :
'use strict';
module.exports = (sequelize, DataTypes) => {
const Service = sequelize.define('Service', {
name: {
type: DataTypes.STRING,
allowNull: false
}
}, {});
Service.associate = function (models) {
Service.belongsTo(models.Experience, {
foreignKey: 'id',
onDelete: 'CASCADE'
});
};
return Service;
};

SequelizeJS Cannot read property 'getTableName' of undefined

I am running into an issue where I am trying to associate two models that have a one-to-many relationship. For some reason this query is throwing an error despite referencing the relationship.
Here is my error message:
Unhandled rejection TypeError: Cannot read property 'getTableName' of undefined
at generateJoinQueries (/Users/user/Desktop/Projects/node/project/node_modules/sequelize/lib/dialects/abstract/query-generator.js:1181:43)
This is the route:
appRoutes.route('/settings')
.get(function(req, res, organization){
models.DiscoverySource.findAll({
where: {
organizationId: req.user.organizationId
},
include: [{
model: models.Organization, through: { attributes: ['organizationName', 'admin', 'discoverySource']}
}]
}).then(function(organization, discoverySource){
res.render('pages/app/settings.hbs',{
organization: organization,
discoverySource: discoverySource
});
})
});
DiscoverySource:
module.exports = function(sequelize, DataTypes) {
var DiscoverySource = sequelize.define('discovery_source', {
discoverySourceId: {
type: DataTypes.INTEGER,
field: 'discovery_source_id',
autoIncrement: true,
primaryKey: true
},
discoverySource: {
type: DataTypes.STRING,
field: 'discovery_source_name'
},
organizationId: {
type: DataTypes.TEXT,
field: 'organization_id'
},
},{
freezeTableName: true,
classMethods: {
associate: function(db) {
DiscoverySource.belongsTo(db.Organization, {foreignKey: 'organization_id'});
},
},
});
return DiscoverySource;
}
Organization:
module.exports = function(sequelize, DataTypes) {
var Organization = sequelize.define('organization', {
organizationId: {
type: DataTypes.INTEGER,
field: 'organization_id',
autoIncrement: true,
primaryKey: true
},
organizationName: {
type: DataTypes.STRING,
field: 'organization_name'
},
admin: DataTypes.STRING
},{
freezeTableName: true,
classMethods: {
associate: function(db) {
Organization.hasMany(db.DiscoverySource, {foreignKey: 'organization_id'});
},
}
});
return Organization;
}
It seems, that's a duplicate of Sequelize Association Error Cannot read property 'getTableName' of undefined.
However, you need to rewrite your query to look like:
models.DiscoverySource.findAll({
attributes: ['discoverySource'],
where: {
organizationId: req.user.organizationId
},
include: [{
model: models.Organization,
attributes: ['organizationName', 'admin']
}]
})
According to the Sequelize documentation:
[options.attributes] - A list of the attributes that you want to select, or an object with include and exclude keys.
[options.include[].attributes] - A list of attributes to select from the child model.
[options.include[].through.where] - Filter on the join model for belongsToMany relations.
[options.include[].through.attributes] - A list of attributes to select from the join model for belongsToMany relations.
So, [options.include[].through] can only be used in case of Belongs-To-Many association rather than Belong-To used by you for DiscoverySource and Organization models.

Resources