티스토리 뷰

Node.js

[error] Sequelize A is not associated to B

bearn_soo 2024. 11. 19. 14:01

시퀄라이즈를 이용해 도메인 모델을 조회할때 매핑된 유저모델을 함께 가지고오려고 했는데 해당 오류가 발생했다.

API서버에 유저가 도메인을 등록하면 API서버는 토큰을 발급해주는 기능으로 유저는 여러개의 도메인을 보유할 수 있고 하나의 도메인은 하나의 유저만 소유할 수 있게 해 일대다 관계로 매핑이 되어있었다.

  • `models/user.js`
// models/user.js
const Sequelize = require("sequelize");

class User extends Sequelize.Model {
  static initiate(sequelize) {
    User.init(
      {
        email: {
          type: Sequelize.STRING(40),
          allowNull: true,
          unique: true,
        },
        nick: {
          type: Sequelize.STRING(15),
          allowNull: false,
        },
        password: {
          type: Sequelize.STRING(100),
          allowNull: true,
        },
        provider: {
          type: Sequelize.ENUM("local", "kakao"),
          allowNull: false,
          defaultValue: "local",
        },
        snsId: {
          type: Sequelize.STRING(30),
          allowNull: true,
        },
      },
      {
        sequelize,
        timestamps: true,
        underscored: false,
        modelName: "User",
        tableName: "users",
        paranoid: true, // deleteAt 유저 삭제일 // soft delete
        charset: "utf8",
        collate: "utf8_general_ci",
      }
    );
  }
  static associate(db) {
    db.User.hasMany(db.Post);
    db.User.belongsToMany(db.User, {
      // 팔로워: 누구를 팔로우했는지
      foreignKey: "followingId",
      as: "Followers",
      through: "follow",
    });
    db.User.belongsToMany(db.User, {
      // 팔로잉: 누구에게 팔로우를 받았는지
      foreignKey: "followerId",
      as: "Followings",
      through: "follow",
    });
    db.User.hasMany(db.Domain);
  }
}

module.exports = User;
  • `models/domain.js`
// models/domain.js
const Sequelize = require("sequelize");

class Domain extends Sequelize.Model {
  static initiate(sequelize) {
    Domain.init(
      {
        host: { type: Sequelize.STRING(80), allowNull: false },
        type: { type: Sequelize.ENUM("free", "premium"), allowNull: false },
        clientSecret: {
          type: Sequelize.UUID,
          allowNull: false,
        },
      },
      {
        sequelize,
        timestamps: true,
        paranoid: true,
        modelName: "Domain",
        tableName: "domains",
      }
    );
  }

  static associations(db) {
    db.Domain.belongsTo(db.User);
  }
}

module.exports = Domain;

 

`models/index.js`에서 `User` 모델과 `Domain` 모델을 정의하고 연관 관계를 매핑해준다.

  • `models/index.js`
const Sequelize = require("sequelize");
const fs = require("fs");
// models/index.js
const path = require("path");
const env = process.env.NODE_ENV || "development";
const config = require("../config/config")[env];
const db = {};
const sequelize = new Sequelize(
  config.database,
  config.username,
  config.password,
  config
);
db.sequelize = sequelize;

const basename = path.basename(__filename);
fs.readdirSync(__dirname)
  .filter((file) => {
    return (
      file.indexOf(".") !== 0 && file !== basename && file.slice(-3) == ".js"
    );
  })
  .forEach((file) => {
    const model = require(path.join(__dirname, file));
    db[model.name] = model;
    model.initiate(sequelize);
  });

Object.keys(db).forEach((modelName) => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

module.exports = db;
  • `controllers/v1.js`
const jwt = require("jsonwebtoken");
const { Domain, User } = require("../models");

exports.createToken = async (req, res) => {
	const { clientSecret } = req.body;
	const domain = await Domain.findOne({
    	where: { clientSecret },
		include: {
        	model: User,
			attribute: ["nick", "id"],
		},
	});
   ...
};

 

`Domain.fineOne` 메서드를 호출할때 `include` 속성에 `User` 모델을 넣었을때 User is not associated Domain! 에러가 발생했다.

Sequelize is not associated to 에러가 발생하는 것은 연관관계가 매핑이 제대로 되지 않았기 때문에 발생한다. 그래서 처음에 내가 생각했던 원인들은 다음과 같다.

  • 캐싱문제: 캐시에 남아있어 매핑을 반영 안했을 가능성
  • 별칭문제: 직접적으로 어떤 테이블을 참조하는지를 명시 안해서 못찾는것인지
  • `models/index.js`에서 `Model.associate` 메서드가 제대로 실행이 안됐을 가능성

캐싱문제는 서버를 재시작하면 캐시가 날아가기 때문에 바로 확인해봤지만 아니였다.

별칭 문제도 다음과 같이 명시해줬지만 원인이 아니였다.

// models/domain.js
db.Domain.belongsTo(db.User, { foreignKey: "userId", targetKey: "id" });

// models/user.js
db.User.hasMany(db.Domain, { foreignKey: "userId" });

세번째 `Model.associate` 메서드가 제대로 실행이 안됐을 경우가 어떤것이 있는지 봤을때 모델 정의보다 모델 매핑이 먼저 됐을 경우가 있을텐데 그것도 아니었다. 그래서 한참 해매다가 찾은것은.... `models/domain.js` 클래스 모델의 `accociate`메서드가 `accociations`으로 오타가 있었다... 그래서 당연히 `models/index.js`에서는 `accociate`를 호출하고 있으니 매핑작업이 안이루어지고 있었던거다....

// models/domain.js

// 오타가 난 매서드
static association(db) {
	db.Domain.belongsTo(db.User);
}

// 다시 메서드 이름을 수정
static associate(db) {
	db.Domain.belongsTo(db.User);
}

 

정말 어이없는 실수로 삽질을 오래했다...

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함