Doing to joins on a table that already has an alias - node.js

I have an association on a self referencing table which requires an alias.
I'm currently trying to query the table twice. However I'm running into a
Transaction (OneTimeDebits) is not associated to Transaction! error.
It seems that since the self referencing association requires an alias there is no way to query the association with a different alias.
Is there some way I can get around this?
models.Transaction.hasMany(models.Transaction, { as: 'Debits', foreignKey: 'PaymentId' });
models.Transaction.belongsTo(models.Transaction, { as: 'Payment', foreignKey: 'PaymentId' });
models.Transaction.findAll({
where: {
'$OneTimeDebits.id$': null,
},
include: [{
model: models.Transaction,
where: {
OneTime: true,
},
required: false,
as: 'OneTimeDebits',
},
{
model: models.Transaction,
where: {
FinalDebit: true,
},
as: 'FinalDebits',
}],
});

Related

Sequelize: Includes not working on defaultScope when querying an object through belongsToMany association

I am trying to move an include object to the default scope of my model CommodityContract. However, when I do this, sequelize throws me an error upon querying results:
'Include unexpected. Element has to be either a Model, an Association or an object.'
Here is my block of code, which works perfectly if I put it inside a custom scope.
defaultScope: {
include: [
{
model: sequelize.models.CommodityContractPayments,
required: false
},
{
model: sequelize.models.CommodityContractTreatmentCharges,
required: false
},
{
model: sequelize.models.CommodityContractRefiningCharges,
required: false
},
{
model: sequelize.models.CommodityContractPriceParticipation,
required: false
},
]
}
The problem is that I am trying to query this specific model as a through object in a belongs-to-many association, and therefore I'm not sure how to apply a scope when querying, unless I do another separate query, which I was trying to avoid.
The main query looks like this:
const contract = await Contract.findOne(
{
where: { id },
include: [
sequelize.models.Commodity,
sequelize.models.ContractSubstance,
sequelize.models.Client,
sequelize.models.Invoice.scope('default_includes')
]
})
Where Commodity is linked to Contract through CommodityContract:
Commodity.belongsToMany(models.Contract, {
through: models.CommodityContract,
foreignKey: 'commodity_id',
otherKey: 'contract_id'
})
And the scope 'default_includes' is defined as such, within the model Invoice:
scopes: {
default_includes: () => {
return {
include: [
{
model: sequelize.models.InvoiceVersion,
required: false
},
{
model: sequelize.models.Contract,
required: false,
},
{
model: sequelize.models.User,
required: false,
},
]
}
}
}
I have had this problem quite a few times before and it annoys me greatly. Sometimes the includes work in a defaultScope, but sometimes it doesn't. Something tells me this has to do with the many-to-many association, but I am not sure.
Any help would be greatly appreciated!

How to solve "Not unique table/alias"? (node, sequelize)

I am implementing a comment service using 'express' and 'sequelize' modules. This comment service supports 'reply'. The model has 'user' and 'comment'.
Comment.hasMany(Comment, {foreignKey: {name: 'parent_comment', allowNull: true}, as: 'reply'});
Comment.belongsTo(Comment, {foreignKey: {name: 'parent_comment', allowNull: true}, as: 'parent'});
User.hasMany(Comment, {foreignKey: {allowNull: false}, onDelete: 'CASCADE'});
Comment.belongsTo(User, {foreignKey: {allowNull: false}, onDelete: 'CASCADE'});
I want to join the user by bringing in the "reply" part of the comment. like below...
[
{
somedata...,
writer: { // User model
userdata....
},
reply: [
{
somedata....
writer: { // User model
userdata....
}
},
....
]
},
....
]
However, as a result, an error occurs while outputting a message of 'Not unique table/alias'. Erase the marked 'this line' part and bring it normally, but it's not the desired result. code like this,
const c = await Comment.findAll({
include: [
{
model: User
},
{
model: Comment,
include: [{ model: User}] //// this line!
},
]
});
How can I get the results I want? Thank you.
Because Comment has 2 relationships with Comment (of course with aliases) you always need to indicate a desired alias in queries when you need to include Comment in Comment:
const c = await Comment.findAll({
include: [
{
model: User
},
{
model: Comment,
as: 'reply', // or as: 'parent' depending on your goal
include: [{ model: User}]
},
]
});

Nested associated data through Sequelize join tables

Using Sequelize, I'm trying to get an output like this:
[{
"Id": 1,
"Name": "Game 1",
"Teams": [{
"Id": 1,
"Name": "Team 1",
"Users": [{
"Id": 1,
"UserName": "User 1"
}]
}]
}, {
"Id": 2,
"Name": "Game 2",
"Teams": [{
"Id": 1,
"Name": "Team 1",
"Users": [{
"Id": 2,
"UserName": "User 2"
}]
}]
}]
Note that Team 1 has 2 different users, but that's only because they're set up that way per game... so a user isn't tied directly to a team, but rather through a team game constraint. Basically, my Game HasMany Teams, and my Game/Team HasMany Users... a many-to-many-to-many relationship. I was trying to follow this thread, but it seems like what they're doing there doesn't actually work, as I tried doing this:
// models/Game.js
module.exports = (sequelize, types) => {
const GameModel = sequelize.define('Game', {
Id: {
type: types.INTEGER,
primaryKey: true,
autoIncrement: true
},
Name: {
type: types.STRING,
allowNull: false
}
});
GameModel.associate = (models) => {
GameModel.belongsToMany(models.Team, {
as: 'Teams',
foreignKey: 'GameId',
through: models.GameTeam
});
};
return GameModel;
};
// models/Team.js
module.exports = (sequelize, types) => {
const TeamModel = sequelize.define('Team', {
Id: {
type: types.INTEGER,
primaryKey: true,
autoIncrement: true
},
Name: {
type: types.STRING,
allowNull: false
}
});
TeamModel.associate = (models) => {
TeamModel.belongsToMany(models.Game, {
as: 'Games',
foreignKey: 'TeamId',
through: models.GameTeam
});
};
return TeamModel;
};
// models/User.js
module.exports = (sequelize, types) => {
const UserModel = sequelize.define('User', {
Id: {
type: types.INTEGER,
primaryKey: true,
autoIncrement: true
},
UserName: {
type: types.STRING,
allowNull: false
}
});
return UserModel;
};
// models/GameTeam.js
module.exports = (sequelize, types) => {
const GameTeamModel = sequelize.define('GameTeam', {
Id: {
type: types.INTEGER,
primaryKey: true,
autoIncrement: true
}
});
GameTeamModel.associate = (models) => {
GameTeamModel.belongsToMany(models.User, {
as: 'Users',
through: 'GameTeamUser'
});
};
return GameTeamModel;
};
The above models create the tables just fine, with what appears to be the appropriate columns. I then do some inserts and try to use a findAll on the Game model like this:
GameModel.findAll({
include: [{
association: GameModel.associations.Teams,
include: [{
association: GameTeamModel.associations.Users,
through: {
attributes: []
}
}],
through: {
attributes: []
}
}]
});
The query starts to go wrong at the 2nd include with the association of the Users. Because I'm trying to nest the users inside of the teams, I figured the join would attempt to use the unique ID on the through table (GameTeams.Id), but instead, the query ends up using this:
LEFT OUTER JOIN `GameTeamUser` AS `Teams->Users->GameTeamUser` ON `Teams`.`Id` = `Teams->Users->GameTeamUser`.`GameTeamId`
I figured the ON would be GameTeams.Id = Teams->Users->GameTeamuser.GameTeamId, but I don't know why it's not, and how to adjust it... I've tried using a custom on in my include (per the docs), but it seems to be ignored completely. Anyone have any advice? Or possibly a better way of structuring this, so it works the way I want it to?
I think you are overcomplicating this thinking you have a many to many to many..and i can see that the fields for your model for GameTeam do not match up with the foreign keys you have declared in your other models...
What do your database tables look like?
Am i correct in saying, that a game has many teams, and a team has many users... however a user can only be on one team at a time, and a team is only in one game at a time? (i am assuming the game/team join and the team/user join are simply temporary records in the join tables disappearing after the game is over etc)

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']
}
}]
})

Sequelize query on join table

I am trying to querying a join table using sequelize:
Here is the model:
db.client.belongsToMany(db.user, {
through: db.clientUser,
onDelete: 'cascade',
});
db.user.belongsToMany(db.client, {
through: db.clientUser,
});
and this is what I am trying to do:
db.user.findAll({
where: {
group_id: 1,
},
include: [{
model: db.clientUser,
where: {
is_manager: 1,
}
}],
raw: true,
})
However I get the following error: client_user is not associated to user!
Any idea what could be the cause of this issue?
You declared a relationship between client from user through clientUser. Although pedantic, its complaint is technically correct: there is no explicitly declared relationship declared between client and clientUser. Nor should there be: your belongsToMany relationship should take care of that. Your query can be adjusted to work with this relationship.
Note: I don't know what tables group_id and is_manager are found in. They may need to be shuffled around.
db.user.findAll({
where: {
group_id: 1,
},
include: [{
model: db.client,
through: {
where: {
is_manager: 1, // Assuming clientUser.is_manager?
},
}],
raw: true,
})

Resources