如何select parent item based on association in sequelize

How to select parent item based on the association in sequelize

我有一个仪器和仪器映射 table。一些仪器在仪器映射 table 中有条目。在映射 table 中,有 true 或 false 的状态。 可以在映射 table 中以任何随机状态 (true/false) 多次重复单个乐器。此外,有些仪器在映射 table. 中没有条目,我需要从有效负载主体中获取以下条件

  1. 获取所有工具
{
   "instrumentStatus": "",
   "searchText": ""
}
  1. 获取所有仅在仪器映射 table 中且状态为 true 的仪器,即使映射 table 包含该特定仪器的错误条目。
{
   "instrumentStatus": true,
   "searchText": ""
}
  1. 获取所有仪器,不包括仪器映射 table 中状态为 true 的仪器 -- 这是重要而复杂的一个。映射 table 包含单个仪器的许多 true 和 false 状态。因此,我们需要获取映射 table 中不存在的所有工具以及映射 table
  2. 中不具有真实状态的工具
{
   "instrumentStatus": false,
   "searchText": ""
}

仪器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;

}

仪器映射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;

}

根据条件获取工具的代码

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 =>

所有案例:require: false

情况 1:根本没有 where 条件

案例二:

where: {
  '$"InstrumentMap".status$': true
}

案例 3:

where: {
   [Op.or]: [
   {
    '$"InstrumentMap".id$': null
   },
   {
    '$"InstrumentMap".status$': false
   }
   ]
}

查看案例一、案例二、案例三,你要抓取的是

情况 1:即使没有 instrument_map,您也想获取所有乐器。 => 左连接。

情况 2:您只需要 instrument_map 状态 == true。 => 内连接

情况 3:即使没有 instrument_map,您也想获取所有乐器。 => 左连接。但是,排除任何具有 1 个或多个 instrument_map 且状态 = 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)
    }]
});