'Sequelize: Querying a through table
I'm trying to query a through table (Application) and paginate/order the results, but can't seem to get the logic quite right.
The Many-To-Many association:
// Applicants M:N Jobs (through Application)
Applicant.belongsToMany(Job, { through: Application });
Job.belongsToMany(Applicant, { through: Application });
I've queried Application, and then nested the queries for each side of the relation:
exports.getApplications = async (req, res, next) => {
const index = req.query.index || 0;
const limit = req.query.limit || 10;
const applications = await Application.findAll({ limit: parseInt(limit, 10), index: parseInt(index)});
let results = [];
try {
await Promise.all(applications.map(async (application) => {
const job = await Job.findOne({ where: { id: application.jobId } });
const applicant = await Applicant.findOne({ where: { id: application.applicantId } });
results.push({application, job, applicant});
}));
res.status(200).json({msg: 'success', applications: results});
} catch(err) {
console.log(err);
}
}
It seems to work, but feels a bit hacky. Is there a way of querying the through table and getting the associated data from both the Jobs and Applicant tables at the same time?
Thanks!
*EDIT: So I'm trying to return an array of application objects that look something like this:
[
{
applicationId: application.id,
companyId: job.companyId,
company: job.company.name,
position: job.title,
applicantId: applicant.id,
firstName: applicant.firstName,
lastName: applicant.lastName,
},
{...},
{...}
]
...but I'd like to paginate the application results. So:
Application.findAll({ limit, index });
Ideally I'd also then like to be able to order by Job/Applicant properties too
More info:
So thanks to the help so far it looks like I need to also create a belongsTo association for the Application and Job/Applicant so that I can query the Association table and get Job/Applicant data:
// Applicants M:N Jobs (through Application)
Applicant.belongsToMany(Job, { through: Application });
Job.belongsToMany(Applicant, { through: Application });
// Set associations so the Application table can be queried directly
Application.belongsTo(Job, { foreignKey: { name: 'jobId' }});
Application.belongsTo(Applicant, { foreignKey: { name: 'applicantId' }});
I currently create an application in one of my routes using applicant.addJob(currentJob);
// Applicant Model:
const Applicant = sequelize.define('applicant', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
cvUrl: {
type: Sequelize.STRING,
allowNull: true
}
});
// Job Model:
const Job = sequelize.define('job', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
title: {
type: Sequelize.STRING,
allowNull: false
},
// **snip**
createdAt: {
type: Sequelize.DATE(3),
allowNull: false,
},
updatedAt: {
type: Sequelize.DATE(3),
allowNull: false,
}
});
// Application Model:
const Application = sequelize.define('application', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
notNull: true
}
});
Solution 1:[1]
With the combination of previous answers
Applicant.belongsToMany(Job, { through: Application ,as:'jobs'});
Job.belongsToMany(Applicant, { through: Application,as:'applicants' })
with these aliases, you can include both into the application
const applications = await Application.findAll({
include: [
{model: Job, as:'jobs', where: {id: application.jobId}},
{model: Applicant, as:'applicants' where:{id: application.jobId}}
],
limit,
raw: true
});
also, you can set include as if applicant and job has an association
{model: Job, as:'jobs', where: {id: application.jobId}
include:[{model:Applicant as:'applicants'}]
}
Solution 2:[2]
You can give aliases tou your associations and just get
Applicant.belongsToMany(Job, { through: Application ,as:'jobs'});
Job.belongsToMany(Applicant, { through: Application,as:'applicants' });
Then you'll be able to use a simple include for example Get the job and its applicants with one single query
const job = await Job.findOne({
where: { id: application.jobId },
include: ['applicants'],
});
in your job object you'll get an array of applicants .
More reference for that in here
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Sertachak |
| Solution 2 | nermineslimane |
