You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Sequelize关联查询员工与休假数据异常问题求助

问题描述

通过nomorInduk字段关联查询Karyawan(员工)和Cuti(休假)数据,已配置模型关联,但查询结果不符合预期。

相关代码

Karyawan 模型文件

'use strict';

module.exports = (sequelize, DataTypes) => {
  const Karyawan = sequelize.define('Karyawan', {
    nomorInduk: DataTypes.STRING,
    nama: DataTypes.STRING,
    alamat: DataTypes.STRING,
    tanggalLahir: DataTypes.DATE,
    tanggalBergabung: DataTypes.DATE
  }, {});
  Karyawan.associate = function (models) {
    Karyawan.hasMany(models.Cuti, { foreignKey: 'nomorInduk' });
  };
  return Karyawan;
};

模型入口文件

'use strict';

const Sequelize = require('sequelize');
const dotenv = require('dotenv');
const db = {};

const KaryawanModel = require('./karyawan');
const CutiModel = require('./cuti');

dotenv.config();

const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, {
    host: process.env.DB_HOST,
    dialect: 'mysql',
    logging: console.log
  });
  
  sequelize.sync({ force: false })
  .then(() => {
      console.log('Database synchronized');
  })
  .catch((error) => {
      console.error('Failed to synchronize database:', error);
  });

  const Karyawan = KaryawanModel(sequelize, Sequelize);
  const Cuti = CutiModel(sequelize, Sequelize);

db.sequelize = sequelize;
db.Sequelize = Sequelize;

// Set up associations inside the models
Karyawan.associate({ Cuti });
Cuti.associate({ Karyawan });

module.exports = { db, Karyawan, Cuti };

Cuti 模型文件

'use strict';

module.exports = (sequelize, DataTypes) => {
  const Cuti = sequelize.define('Cuti', {
    nomorInduk: DataTypes.STRING,
    tanggalCuti: DataTypes.DATE,
    lamaCuti: DataTypes.INTEGER,
    keterangan: DataTypes.TEXT
  }, {});
  Cuti.associate = function (models) {
    Cuti.belongsTo(models.Karyawan, { foreignKey: 'nomorInduk' });
  };
  return Cuti;
};

查询处理函数

async function getKaryawanByNomorInduk(req, res) {
    try {
        const nomorInduk = req.params.nomorInduk;

        const karyawan = await models.Karyawan.findOne({
            where: {
                nomorInduk: nomorInduk
            },
            include: [{
                model: models.Cuti,
                attributes: ['id', 'nomorInduk', 'tanggalCuti', 'lamaCuti', 'keterangan'],
            }],
        });

        if (!karyawan) {
            return res.status(404).json({ message: 'Tidak ada data karyawan dengan nomor induk tersebut.' });
        }

        const result = {
            status: 'ok',
            data: karyawan,
        };

        res.json(result);
    } catch (error) {
        res.status(500).json({ message: 'Gagal mendapatkan data karyawan.', error: error.message });
    }
}

结果差异

  • 当前返回:单个员工对象,其中包含一个Cuti数组,数组内是该员工的所有休假记录
  • 期望返回:多条数据,每条数据同时包含员工信息和单条休假信息(类似SQL JOIN后的扁平化结果)

解决方案

问题出在使用了findOne和默认的关联查询格式,调整查询方式即可得到扁平化的JOIN结果:

修改后的查询处理函数

async function getKaryawanByNomorInduk(req, res) {
    try {
        const nomorInduk = req.params.nomorInduk;

        // 使用findAll + raw: true 获取扁平化的JOIN结果
        const karyawanCutiList = await models.Karyawan.findAll({
            where: {
                nomorInduk: nomorInduk
            },
            include: [{
                model: models.Cuti,
                attributes: ['id', 'tanggalCuti', 'lamaCuti', 'keterangan'],
                required: false // 允许员工无休假记录时也返回数据
            }],
            raw: true, // 直接返回数据库原始查询数据,不包装为模型实例
            nest: false // 将关联字段扁平化到顶层,而非嵌套结构
        });

        if (karyawanCutiList.length === 0) {
            return res.status(404).json({ message: 'Tidak ada data karyawan dengan nomor induk tersebut.' });
        }

        const result = {
            status: 'ok',
            data: karyawanCutiList,
        };

        res.json(result);
    } catch (error) {
        res.status(500).json({ message: 'Gagal mendapatkan data karyawan.', error: error.message });
    }
}

关键调整说明

  1. 替换findOne为findAll:适配一个员工对应多条休假记录的场景,返回多条结果
  2. 添加raw: true:跳过Sequelize的模型实例包装,直接返回数据库查询的原始数据
  3. 设置nest: false:将关联的Cuti字段扁平化到顶层,避免嵌套结构
  4. 调整Cuti的attributes:移除重复的nomorInduk字段,避免结果中出现冗余数据
  5. 可选required: false:若需要在员工无休假记录时仍返回员工信息则保留;若仅需返回有休假记录的员工,可删除该配置

内容的提问来源于stack exchange,提问作者NinjaTea0161

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 23:53:23