SequelizeAssociationError after second call - node.js

I'm using a NodeJS webservice to receive my database data. If I call the methode the first Time everything works as expected.
I want to receive all entries from my table with all associations with the following Code:
model.hasOne(devicemodel, {foreignKey: 'id',sourceKey:'deviceid'});
model.hasOne(usermodel, {as: 'client', foreignKey: 'id' ,sourceKey: 'clientid'});
model.hasOne(usermodel, {as: 'operator', foreignKey: 'id' ,sourceKey: 'operatorid'});
var rma = await model.findAll({
include: [devicemodel, {model: usermodel, as: 'client'}, {model: usermodel, as: 'operator'}],
where: {
itoakid: config.companyid
}
});
return callback(rma);
But at the second call I get the following error:
SequelizeAssociationError: You have used the alias client in two separate associations. Aliased associations must have unique aliases.
I'm using Sequelize Version 6.11.3

In case you need to define the associations in your route, you can check existing associations prior to define.
alternative way,
model.hasOne(devicemodel, {foreignKey: 'id',sourceKey:'deviceid'});
if( !model.hasAlias('client') ){
model.hasOne(usermodel, {as: 'client', foreignKey: 'id' ,sourceKey: 'clientid'});
}
if(!model.hasAlias('operator')){
model.hasOne(usermodel, {as: 'operator', foreignKey: 'id' ,sourceKey: 'operatorid'});
}
var rma = await model.findAll({
include: [devicemodel, {model: usermodel, as: 'client'}, {model: usermodel, as: 'operator'}],
where: {
itoakid: config.companyid
}
});
return callback(rma);
The best way, you should define associations once as #Samuel G mentioned

You are defining the associations every time the route is hit and your function executes.
Move the schema declaration out the route handler and place it after you define your schema:
class Model extends Sequelize.Model {}
Model.init({
id: {
primaryKey: true,
type: Sequelize.UUID
},
...
}, {
sequelize,
modelName: 'model'
});
sequelize.models.model.hasOne(...
In your route handler:
var rma = await sequelize.models.model.findAll({
include: [devicemodel, {model: sequelize.models.usermodel, as: 'client'},

Related

How do I eager load multiple foreign keys including an or query from the same table, in Sequelize?

I'm searching for the captain.entry_date but I'm not able to create the query in a sequelize model.
My problem is that for any ship exists a captain but the ship_captain.captain_id sometimes is null.
For this cases the captain can be found about the route_id.
4 Tables :
ship, attributes:[id,name],
captain, attributes: [id, name, route_id, route_date]
ship_captain, attributes: [id, ship_id, route_id, captain_id]
route, attributes: [id, name]
select ship.name, c.name, c.entry_date
from ship left join ship_captain sc on ship.id = sc.ship_id
left join captain c on c.id = sc.captain_id or c.route_id = sc.route_id
What I've try so far is this but I can't give an OR operator into the last join
Ship.hasMany(ShipCaptain, {foreignKey: "ship_id"});
ShipCaptain.belongsTo(Ship, {foreignKey: "ship_id"});
Captain.hasMany(ShipCaptain, {as: "ship_captain_by_id", foreignKey: "captain_id"});
ShipCaptain.belongsTo(Captain, {as: "ship_captain_by_route", foreignKey: "captain_id"});
Captain.hasMany(ShipCaptain, {as: "ship_captain_by_route", foreignKey: "route_id"});
ShipCaptain.belongsTo(Captain, {as: "ship_captain_by_route", foreignKey: "route_id"});
const options = {
attributes: ["name"],
include: [
{
model: Captain,
as: 'ship_captain_per_id',
required: false,
attributes: ["name","route_date"],
},
{
model: Captain,
as: 'ship_captain_per_route',
required: false,
attributes: ["name","route_date"],
}
],
}
const elements = await Ship.findAll(options);
This is only an example code, may be that you want to rearrange the db attributes
but I tried to give my best to clarify the problem. I can't change the customers database.
If you really want to use only one association to get a captain by captain_id or route_id and not to use two associations and map them yourself then you need to define only one association hasOne (instead of hasMany) and always use the on option to join ShipCaptain with Captain by OR:
Ship.hasMany(ShipCaptain, {foreignKey: "ship_id"});
ShipCaptain.belongsTo(Ship, {foreignKey: "ship_id"});
ShipCaptain.belongsTo(Captain, {as: "captain_by_captain", foreignKey: "captain_id"});
...
const options = {
attributes: ["name"],
include: [
{
model: ShipCaptain,
required: false,
include: [{
model: Captain,
required: false,
as: 'captain_by_captain',
attributes: ["name","route_date"],
on: {
[Op.or]: [{
id: Sequelize.col('ship_captain.captain_id'
}, {
id: Sequelize.col('ship_captain.route_id'
}]
}
}
]
},
],
}
const elements = await Ship.findAll(options);

Associations HasMany works but HasOne does not

I have two models defined in GraphQL Cars and Brands (their association is cars.brand_id = brands.id).
The schema only works when I define:
Cars.hasMany(models.brands, {
sourceKey: 'brand_id',
foreignKey: 'id'
})
Whereas it doesn't work if I define it in the following way:
Cars.hasOne(models.brands, {
sourceKey: 'brand_id',
foreignKey: 'id'
}),
Here I share a bit more of the schema (I am using makeExecutableSchema to split the files definitions):
Associations:
CarBrands.js
CarBrands.associate = models => {
CarBrands.hasOne(models.cars, {
foreignKey: 'brand_id',
});
}
Cars.js
Cars.associate = models => {
Cars.belongsTo(models.brands),
Cars.hasMany(models.car_images, {
foreignKey: {
name: 'car_id',
allowNull: false
},
onDelete: "cascade"
});
};
Car Model:
export const typeDef = `
type Cars {
user_id: Int!,
title: String!,
brands: [CarBrands!],
car_images: [CarImages],
}
`;
The SQL is well-formed, and car_images returns the data correctly whereas brands does not. Any idea why is that?
Any hint will be forever appreciated.
Thanks
You can find the document one-to-one-relationships at there: https://sequelize.org/master/manual/assocs.html#one-to-one-relationships
.In the document introduces 4 options to define one-to-one.
Try it:
Brands.hasOne(Cars, {
foreignKey: 'brand_id'
});
Cars.belongsTo(Brands);

Multiple Sequelize Associations

I have a few associations between models like so:
Patient.hasMany(Transaction, {
as: 'transactions',
foreignKey: 'patient_id',
sourceKey: 'id'
});
Transaction.belongsTo(Patient, {
as: 'patient',
foreignKey: 'patient_id',
targetKey: 'id'
});
Transaction.hasMany(Transaction, {
as: 'transactions',
foreignKey: 'item_to_pay',
sourceKey: 'id'
});
I'm writing a query to get a list of transactions that belong to a patient and include the models associated with them:
Transaction.findAll({
where: {
patient_id: 1
},
include: [{
model: Patient,
as: 'patient',
attributes: ['first_name']
}, {
model: Transaction,
as: 'transactions',
include: [{
model: Patient,
as: 'patient',
attributes: ['first_name']
}]
}],
});
However when the result returns, it does not include the second nested patient model as I expect it to.
I've also tried writing a different query to see if I can get the desired result:
Transaction.findAll({
where: {
patient_id: 1
},
include: [{
model: Transaction,
as: 'transactions',
include: [{
model: Patient,
as: 'patient',
attributes: ['first_name']
}]
}],
});
But this query errors out and returns 'Unknown column 'patient.id' in field list'.
Does anyone see something wrong with my query or associations? Is there something I'm not understanding about the associations here?
I ended up changing my original query since I couldn't figure it out at the time. I stumbled into the same issue recently and realized the issue came from how I named my associations. I named the transaction.hasMany association as transactions which ended up confusing MySQL with the query that was generated because one of the tables is named transactions.
TLDR, don't name your associations the same name as any of your table names.

In Nodejs I keep getting Sequelize.js - “is not associated to” error

I have the following 2 tables in node.js:
users
'use strict'
let Sequelize = require('sequelize');
let dbConnection = require('../connection.js');
let users = dbConnection.connection.define('users', {
//user table detail
}, {
classMethods: {associate: function (models) {
// associations can be defined here
users.hasMany(models.chat_histories, {foreignKey: 'sender_id'});
users.hasMany(models.chat_histories, {foreignKey: 'receiver_id'});
}}
}, {
timestamps: false
});
module.exports = users;
chat_histories
'use strict'
let Sequelize = require('sequelize');
let dbConnection = require('../connection.js');
let chat_histories = dbConnection.connection.define(
'chat_histories', {
//chat_history detail
link_id: {
type: Sequelize.STRING(64),
references: 'links', // <<< Note, its table's name, not object name
referencesKey: 'id' // <<< Note, its a column name
},
sender_id: {
type: Sequelize.BIGINT,
references: 'users', // <<< Note, its table's name, not object name
referencesKey: 'id' // <<< Note, its a column name
},
receiver_id: {
type: Sequelize.BIGINT,
references: 'users', // <<< Note, its table's name, not object name
referencesKey: 'id' // <<< Note, its a column name
}
},
{
classMethods: {associate: function (models) {
// associations can be defined here
chat_histories.belongsTo(models.users, {foreignKey: 'sender_id'});
chat_histories.belongsTo(models.users, {foreignKey: 'receiver_id'});
chat_histories.belongsTo(models.links, {foreignKey: 'link_id' });
}}
}, {
timestamps: false
}
);
module.exports = chat_histories;
However, every time when I do query in chat_history table I have the following error message:
SequelizeEagerLoadingError: chat_histories is not associated to users!
Is there anything wrong?
I can see myself have already associated chat_historeis with users table via adding the following in chat_histories.js
classMethods: {associate: function (models) {
// associations can be defined here
chat_histories.belongsTo(models.users, {foreignKey: 'sender_id'});
chat_histories.belongsTo(models.users, {foreignKey: 'receiver_id'});
chat_histories.belongsTo(models.links, {foreignKey: 'link_id' });
}}
And added the following in user.js
classMethods: {associate: function (models) {
// associations can be defined here
users.hasMany(models.chat_histories, {foreignKey: 'sender_id'});
users.hasMany(models.chat_histories, {foreignKey: 'receiver_id'});
users.hasMany(models.links, {foreignKey: 'owner_id'});
}}
At the following is how I do search for SQL statement:
select distinct users from users, chat_histories where (users.id =
chat_histories.sender_id or users.id = chat_histories.receiver_id) and
chat_histories.link_id = :link_id;
let chat_histories = model.chat_histories;
let users = model.users;
let usersList;
const Op = Sequelize.Op;
await users.findAll({
where: {
[Op.and]: [
{
[Op.or]:[
{id: chat_histories.sender_id},
{id: chat_histories.receiver_id}
]
},
{
link_id: link_id
}
],
},
include: [
{
model: chat_histories,
required: false
},
]
}).then(function(data) {
usersList = data;
});
You have not defined associations properly. Associations need to be created for both users and chat_histories table.
users.hasMany(models.chat_histories, { foreignKey: 'sender_id', as: 'chat_histories' });
chat_histories.belongsTo(models.users, { foreignKey: 'sender_id', as: 'user' });
I have never used keywords like references and referencesKey in Sequelize models to define associations. I neither find any reference for them in the documentation.
Hope it helps!
ok at the end I figured out that in the class where I want to do the query, I need to put the following code before doing the query
users.hasMany(chat_histories, {foreignKey: 'sender_id'});
The above code is defined in the class where I did the query instead of in ORM class

Sequelize: Joining Many to Many tag table with another table in postgresql

I am trying to setup many to many relationship in Sequelize for my Postgres tables using a tag (lookup) table. I was successful in setting up the relationship.
Now my lookup table, has an additional field which is a foreign key to another table. I want the data for that table to be included in my result set. This is where I am having hard time figuring out the syntax.
My models:
Models.user = sequelize.define('user', { //attributes});
Models.school = sequelize.define('school', { //attributes });
Models.role = sequelize.define('role', { //attributes });
Models.userSchools = sequelize.define('user_school', {
user_school_id: { type: Sequelize.INTEGER, primaryKey: true }
});
Models.user.belongsToMany(Models.school, { through: Models.userSchools, foreignKey: 'user_id', otherKey: 'school_id' });
Models.school.belongsToMany(Models.user, { through: Models.userSchools, foreignKey: 'school_id', otherKey: 'user_id' });
Models.userSchools.belongsTo(Models.role, { foreignKey: 'role_id' });
Working query: This query gives me all the users and their schools.
Models.user.findAll({
where: {
//condition
},
include: [Models.school]
})
Now I want to include the role for each schools. None of the below queries are working.
Models.user.findAll({
where: {
//conditions
},
include: [Models.schools, Models.role]
})
Above query is throwing an error saying role is not associated to user, which is expected.
Models.user.findAll({
where: {
//conditions
},
include: [Models.schools, {model: Models.userSchools, include: Models.role}]
})
This query is also throwing an error:
"userSchools is not associated to user".
Can any one help with syntax to how I can get the role information from the userSchools model?
Edit:
I have add a "through" condition which gets me the role_id but not the related role data.
Models.user.findAll({
where: {
//conditions
},
include: [{
model: Models.school,
as: 'schools',
through: {
attributes: ['role_id']
}
}]
})

Resources