i have made two foreign keys from user table.
db.Subscription.belongsTo(db.User, {foreignKey: 'creatorId'});
db.Subscription.belongsTo(db.User, {foreignKey: 'subscriberId'});
during search query i get subscriberId column included instead of creatorId
Subscription.findAll({
where: {
subscriberId: req.decoded._id
},
include: [
{
model: User,
foreignKey: 'creatorId',
attributes: ['name', 'role', 'uid', 'imageUrl']
}
]
})
can someone please find out what i am doing wrong here.
Try setting a name for the associations so Sequelize has a better idea which association to include. You can do something like this to set the names on the associations...
db.Subscription.belongsTo(db.User, {
as: 'creator',
foreignKey: 'creatorId'
});
db.Subscription.belongsTo(db.User, {
as: 'subscriber',
foreignKey: 'subscriberId'
});
Then you can use those names in the query to get the specific association, as so...
Subscription.findAll({
include: {
model: User,
as: 'creator',
attributes: ['name', 'role', 'uid', 'imageUrl']
},
where: {
subscriberId: req.decoded._identer
}
});
When you have associations to the same table more than once setting a name helps the ORM determine which association to load. For the record, for all of the records that get returned you can access that association by accessing the .creator on the instance.
Good luck! :)
Related
my goal here is to add a second join table between two tables :
I got one table User
I got one table Tirage
And I already created a join table Participate,
here is the "associations" and Participate model code :
Participate :
module.exports = (sequelize, Sequelize) => {
const Participe = sequelize.define("participe", {
uuid: {
type: Sequelize.UUID,
primaryKey: true,
defaultValue: Sequelize.UUIDV1,
},
cadeauA: {
type: Sequelize.UUID
},
participantId: {
type: Sequelize.UUID
},
tirageId: {
type: Sequelize.UUID
},
isAdmin: {
type: Sequelize.BOOLEAN
},
selfGranted: Sequelize.BOOLEAN
});
return Participe;
};
Association :
db.users.belongsToMany(db.tirages, {through: db.participe, foreignKey:'cadeauA', foreignKey:'participantId'});
db.tirages.belongsToMany(db.users, {through: db.participe, foreignKey:'tirageId'});
(Note that I didn't check yet if the second foreign key in the first line works, so if it's not it's kinda normal).
It works, I can manage to get all tirages from users who are "participating" thanks to :
exports.getUserInvitation = async (req, res) => {
const user = await User.findOne({
where: {
uuid: req.params.participant
},
include: Tirage,
as: 'tirages'
});
return res.status(200).send(user.tirages);
}
So now, I would like to add an other junction table, not to see if a user is participating to a tirage but if he is invited to the tirage.
I tried mutliple things but it just won't work or even break the "participate" feature.
I read the entire association doc from sequelize but nothing is really helpfull for multiple many-to-many association between two tables.
What I tried :
db.users.belongsToMany(db.tirages, {through: db.invitation, foreignKey:'invite', foreignKey:'admin'});
db.tirages.belongsToMany(db.users, {through: db.invitation, foreignKey:'tirageId'});
db.invitations.belongsTo(db.users, {foreignKey:'admin', foreignKey:'invite'});
db.invitations.belongsTo(db.tirages, {foreignKey:'_tirage'});
And many other things that I don't remember.
Edit :
I would like to say that I tested it :
db.users.belongsToMany(db.tirages, {through: db.invitations, foreignKey:'invite', foreignKey:'admin'});
db.tirages.belongsToMany(db.users, {through: db.invitations, foreignKey:'tirageId'});
but when I do
await user.addTirage(tirage, { through: Invitation });
It adds a Participate record (even if I specify the through table).
First, if you indicate the same key foreignKey twice JS will keep only the last one.
Second, Sequelize does not support composite foreign keys.
Third, to distinguish associations from the same tables to the other same tables you need to indicate aliases in associations and also in each query where you need to include associated models.
Let's assume you use one column from each table to join with junction tables then it might look like this:
db.users.belongsToMany(db.tirages, {through: db.participe, foreignKey:'participantId', as: 'participatingTirages'});
db.tirages.belongsToMany(db.users, {through: db.participe, foreignKey:'tirageId', as: 'participatedUsers'});
db.users.belongsToMany(db.tirages, {through: db.invitations, foreignKey:'invite', as: 'invitatingTirages'});
db.tirages.belongsToMany(db.users, {through: db.invitations, foreignKey:'tirageId', as: 'invitedUsers'});
Now, you can add a tirage with invitation like this (maybe I make mistake in the name of the method, try to find out the real one):
await user.addInvitingTirage(tirage);
OR to add a tirage to participate in:
await user.addParticipatingTirage(tirage);
I am using Sequelize, a nodejs ORM for mysql. Using mysql workbench I made an EEM diagram and pushed that design into the db, so far so good.
Now in Sequelize I have to tell it what the design of the DB looks like, part of that is telling it what foreign keys are called.
In Workbench there is a foreign key tab in the tablethere are variables formatted likefd_positions_tradingPLan1` but I never name that, in fact in my EEM diagram I have
Then if I go to that foreign keys tab at the bottom I get this. I am confused as to exactly what I should tell the ORM the foreign key is...
Let's take your positions Table as reference. To build your model on sequelize you have to do the following:
module.exports = (sequelize, DataTypes) => {
const Position = sequelize.define('Position', { // this is the name that you'll use on sequelize methods, not what you have on your db
// define your columns like this:
tradeName: { //the name of the variable that you'll use on sequelize and js
field: 'trade_name', //the actual name of your column on the table
type: DataTypes.STRING(128) // the data type
},
// .......
// for your foreignKeys you have to define the column like your other attributes.
userId: {
field: 'user_id',
type: DataTypes.INTEGER
},
}, {
tableName: 'positions', //this is the name of your table on the database
underscored: true, // to recognize the underscore names
createdAt: 'created_at', //
updatedAt: 'updated_at',
});
//now for your association let's say that you defined your USER table like this example.
Position.associate = (models) => {
// on the foreignKey value, youhave to put the same that you define above, and on the db.
Position.belongsTo(models.User, { as: 'User', foreignKey: 'user_id' });
//depending on your other relations, you are gonna use hasMany, hasOne, belongsToMany
};
return Position;
};
Sequelize does the association only one way, that means that on this example, you can't query with sequelize from User to Position, to be able to
have two way association you have to defined on both models.
User.associate = (models) => {
// on this case we use hasMany cause user can have many positions I suppose, if not, use hasOne
User.hasMany(models.Poisition, { as: 'positions', foreignKey: 'user_id' }); //remeber to use the same foreignKey name
};
UPDATE:
as is an identfier for Sequelize. Let's say you make two associations for the same model, later when you try to query one of this associations, you can specify the association that you want
User.associate = (models) => {
User.hasMany(models.Poisition, { as: 'positions', foreignKey: 'user_id' });
User.hasMany(models.Poisition, { as: 'customerPositions', foreignKey: 'customer_id' });
};
//the actual association call
User.findAll({
include:[{
model: db.user,
as: 'positions'
}, {
model: db.user,
as: 'customerPositions'
}]
})
Now for fk_positions_users1, this is an identifier for MySQL itself. Sequelize only check for the foreignKey and the models involve. Obviously when Sequelize create the reference, it gives a template name using the table and column name. I tried myself creating a new foreignKey on my table and then updating the model and everything goes fine. You should'nt have problems with that.
I have been trying to define a relationship between 3 tables and then create them all in one create function. For some reason, while creating the 3 models, the linking IDs (foreign keys) are undefined and are not passing on. Here are the associations:
Person.js:
models.person.Lead = models.person.hasMany(models.lead, {
onDelete: "CASCADE",
foreignKey: "person_id"
});
Lead.js:
models.lead.Person = models.lead.belongsTo(models.person, {foreignKey: 'person_id'});
models.lead.Sealant_customer = models.lead.hasOne(models.sealant_customer, {
onDelete: "CASCADE",
foreignKey: 'lead_id'
})
sealantCustomer.js:
models.sealant_customer.Lead = models.sealant_customer.belongsTo(models.lead);
The build function:
let sealantCustomer = models.sealant_customer.build({
address: body.address,
city: body.city,
roof_size: body.roofSize,
last_sealed: body.lastSealed,
existingSealant: body.existingSealant,
leaks_freq: body.leaksFrequency,
floor: body.floor,
elevator: body.elevator,
panels: body.panels,
home_type: body.homeType,
urgency: body.urgency,
next_step: body.nextStep,
more_info: body.moreInfo,
lead: {
site,
url: body.url,
date,
ip: body.ip,
person: {
name: body.name,
email: body.email,
phone: body.phone,
date,
city: body.city ? body.city : undefined,
address: body.address ? body.address : undefined,
}
}
}, {
include: [{
model: models.lead,
association: models.sealant_customer.Lead,
include: [{
model: models.person,
association: models.lead.Person
}]
}]
})
The outputted object is good except for the fact that lead_id and person_id are nulls (Each model has its own ID, but not the associated model's id). I also should note there are no validation errors and the data is good.
The library has a bug in the build function as far as I can tell. Same syntax with create worked perfectly.
In Sequelize v6, the association identifier in the include section is not valid. Otherwise, this build function should properly work.
I've got this pivot table, which represents a many to many relationship with the models Person and Movie.
The thing is I want to get the role when I call the movies that get the persons associated. I tried this but it doesn't show the role :
models.Movie.findAll({
include: [{
model: models.Person,
as: 'persons',
through: {attributes: ["role"]}
}]
}).then(function(movies) {
res.json(movies);
});
Do I have to specify something in the models for the role ?
I finally managed to achieve this by creating a model for the pivot table movie_person with the role attribute as a string.
var MoviePerson = sequelize.define("MoviePerson", {
role: DataTypes.STRING
},
{
tableName: 'movie_person',
underscored: true
});
Then in my Movie model I added this
Movie.belongsToMany(models.Person, {
through: models.MoviePerson,
foreignKey: 'movie_id',
as: 'persons'
});
I had to do something obviously similar to this in my Person model and that's it !
For the purpose of those who will need this, there is a new method called 'magic methods'. I believe you have declared your many-to-many asociation
const movies = Movie.findAll();
const person = Person.findbyPk(personId);
const moviesPerson = movies.getPersons(person);
Using sequelize, I expect this line:
m.User.belongsToMany(m.Company, {through: 'UserCompany'});
to generate a new table in my database called 'user_company' that would link the 'user' table and the 'company' table together. However, it isn't doing that. Am I misunderstanding the documentation when it says
This will create a new model called UserProject with with the
equivalent foreign keys ProjectId and UserId. Whether the attributes
are camelcase or not depends on the two models joined by the table (in
this case User and Project).
or am I doing something wrong?
Here are the relations I am setting up
m.Company.hasMany(m.User);
m.User.belongsToMany(m.Company, {
through: m.UserCompany
});
m.User.sync({force: true, match: /_test$/});
m.Company.sync({force: true, match: /_test$/});
m.UserCompany.sync({force: true, match: /_test$/});
Looks like I needed to create the UserCompany model manually. So, UserCompany.js looks like:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('UserCompany', {
}, {
freezeTableName: true,
paranoid: true
});
}
Then the belongsToMany automatically adds the correct columns to the table.