Reputation: 732
I am having an instrument and instrument mapping table. Some of the instruments have entries in the instrument mapping table. In the mapping table, there is the status with true or false. A single instrument can be repeated multiple times in the mapping table with any random status(true/false). Also some Instruments don't have entry in the mapping table. I need to fetch below conditions from payload body
{
"instrumentStatus": "",
"searchText": ""
}
{
"instrumentStatus": true,
"searchText": ""
}
{
"instrumentStatus": false,
"searchText": ""
}
Instrument table
module.exports = (sequelize, DataTypes) => {
const Instrument = sequelize.define("instrument", {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: { type: STRING },
description: { type: STRING }
}, {
timestamps: false,
freezeTableName: true,
})
Instrument.associate = function (models) {
Instrument.hasMany(models.instrument_map, { as: "InstrumentMap" });
};
return Instrument;
}
Instrument mapping table
module.exports = (sequelize, DataTypes) => {
const InstrumentMap = sequelize.define("instrument_map", {
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
instrumentId: { type: INTEGER },
status: { type: BOOLEAN, defaultValue: 1 },
}, {
timestamps: false,
freezeTableName: true,
})
InstrumentMap.associate = function (models) {
InstrumentMap.belongsTo(models.instrument, { as: "instrument", foreignKey: 'instrumentId' });
};
return InstrumentMap;
}
Code to fetch instruments based on the condition
let condition = [];
if (body.instrumentStatus != null && body.instrumentStatus != "" && body.instrumentStatus) {
condition.push(Sequelize.where(Sequelize.count("InstrumentMap." + "status"), Sequelize.Op.eq, body.instrumentStatus));
}
db.instrument.findAndCountAll({
where: {
[Sequelize.Op.or]: [
Sequelize.where(Sequelize.fn('lower', Sequelize.col("instrument." + "name")), Sequelize.Op.like, '%' + body.searchText + '%'),
Sequelize.where(Sequelize.fn('lower', Sequelize.col("instrument." + "description")), Sequelize.Op.like, '%' + body.searchText + '%')
],
[Sequelize.Op.and]: condition
},
order: [
[Sequelize.fn('lower', Sequelize.col("instrument.name" )), "ASC"]
],
offset: body offset,
limit: lbody.imit,
distinct: true,
subQuery: false,
include: [
{
model: db.instrument_map,
as: 'InstrumentMap',
attributes: ['status'],
required: true,
}
]
}).then(result =>
Upvotes: 1
Views: 266
Reputation: 9308
Looking at Case 1, 2, and 3, what you are fetching is
Case 1: You want to fetch ALL instruments even if there is no instrument_map. => LEFT JOIN.
Case 2: You want only instrument_map with a status == true. => INNER JOIN
Case 3: You want to fetch ALL instruments even if there is no instrument_map. => LEFT JOIN. However, exclude any instrument which has 1 or more instrument_map with status = true.
// Make sure req.body.status is either true or false. If it is not neither true nor false, status becomes undefined.
const status = [true, false].includes(req.body.status) ? req.body.status : undefined;
// Case 1: no condition.
let statusCond;
// Case 3: Get instrument whose instrument_map does NOT EXISTS with status = true.
if (status === false) {
statusCond = Sequelize.literal(`NOT EXISTS ( \
SELECT 1 FROM instrument_map \
WHERE instrument.id = instrument_map.instrumentId \
AND status = true)`)
// Case 2: Filter to status = true only
} else if (status === true) {
statusCond = { '$InsturmentMap.status$': true }
}
db.Instrument.findAndCountAll({
where: {
[Op.or]: [
Sequelize.where(Sequelize.fn('lower', Sequelize.col('name')), Op.like, `%${body.searchText}%`),
Sequelize.where(Sequelize.fn('lower', Sequelize.col('description')), Op.like, `%${body.searchText}%`),
],
[Op.and]: statusCond
},
distinct: true,
include: [{
model: db.InstrumentMap,
as: 'InstrumentMap',
attributes: ['status'],
required: status || false, // Only if req.body.status is true, we need INNER JOIN. Otherwise, LEFT JOIN (required: false)
}]
});
Upvotes: 1
Reputation: 22783
All cases: require: false
Case 1: no where
condition at all
Case 2:
where: {
'$"InstrumentMap".status$': true
}
Case 3:
where: {
[Op.or]: [
{
'$"InstrumentMap".id$': null
},
{
'$"InstrumentMap".status$': false
}
]
}
Upvotes: 1