Search code examples
node.jssequelize.jshas-manybelongs-to

Nodejs using Sequelize. "[].belongsTo called with something that's not a subclass of Sequelize.Model at Function."


[ Learnt knowledge ]

I am following a basic tutorial to learn sequelize and its associations.

And this book shows only hasMany and belongsTo examples.

With the short knowledge, I am hitting a wall to create some data schema.

[ What I am trying to ]

The data schema is basically about military branch(or unit) assoications.

Atom unit is a team. And a team has a direct superior unit - a section.

Or, if a team does not have a section as a direct superior unit, then, its direct superior unit will be a squad.

Squad > ( Section ) > Team

I wrote something, but I got this error.

Error: Section.belongsTo called with something that's not a subclass of Sequelize.Model
    at Function.<anonymous> (/Users/mac/Desktop/modeling/node_modules/sequelize/lib/associations/mixin.js:93:13)

and Here is my code.

model/index.js

const Sequelize = require('sequelize');

const Team = require("./team");
const Section = require("./section");
const Squad = require("./squad");

// const Platoon = require("./platoon");
// const Company = require("./company");
// const Battalion = require("./battalion");
// const Regiment = require("./regiment");
// const Brigade = require("./brigade");
// const Division = require("./division");
// const Corps = require("./corps");
// const Command = require("./command");
// const Unit = require("./branch");

// const DogTag = require("./dogtag");
// const Name = require("./name");
// const Rank = requrie("./rank");
// const Position = require("./position");
// const Branch = requrie("./branch")
// const Soldier = requrie("./soldier");



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;

db.Team = Team;
db.Section = Section;

Team.init(sequelize);
Section.init(sequelize);
Squad.init(sequelize);

Section.associate(db);
Squad.associate(db);
Team.associate(db);

module.exports = db;

model/team.js

const Sequelize = require("sequelize");

module.exports = class Team extends Sequelize.Model{
    static init(sequelize) {
        return super.init({
            name : {
                type : Sequelize.STRING(20), //STING == MySQL VARCHAR
                allowNull : false, // allowNull == MySQL NOT NULL
                unique : true, // unique == UNIQUE
            },
            created_at : {
                type : Sequelize.DATE, // DATE == MySQL DATETIME
                allowNull : false,
                defaultValue : Sequelize.NOW, // defaultValue == MySQL DEFAULT / Sequelize.NOW == now()
            },   // should you want ZEROFILL option, use [INTERGER.UNSIGNED].ZEROFILL
        },{
            sequelize, //connect with model/index.js
            timestamps : false,
            underscored : false, // createdAt => craeted_at
            modelName : 'Team',
            tableName : 'teams',
            paranoid : 'false', // if is true, deletedAt column will be craeted. 
            charset : 'utf8', 
            collate : 'utf8_general_ci',
        });
    }

    static associate(db) {
        db.Team.belongsTo(db.Section, { 
            foreignKey : "sectionID",
            targetKey : 'id' 
        });


        db.Team.belongsTo(db.Squad, { 
            foreignKey : "squadID",
            targetKey : 'id' 
        });
    };
    
}

model/section.js

const Sequelize = require("sequelize");

module.exports = class Section extends Sequelize.Model{
    static init(sequelize) {
        return super.init({
            name : {
                type : Sequelize.STRING(20), //STING == MySQL VARCHAR
                allowNull : false, // allowNull == MySQL NOT NULL
                unique : true, // unique == UNIQUE
            },
            created_at : {
                type : Sequelize.DATE, // DATE == MySQL DATETIME
                allowNull : false,
                defaultValue : Sequelize.NOW, // defaultValue == MySQL DEFAULT / Sequelize.NOW == now()
            },   // should you want ZEROFILL option, use [INTERGER.UNSIGNED].ZEROFILL
        },{
            sequelize, //connect with model/index.js
            timestamps : false,
            underscored : false, // createdAt => craeted_at
            modelName : 'Section',
            tableName : 'sections',
            paranoid : 'false', // if is true, deletedAt column will be craeted. 
            charset : 'utf8', 
            collate : 'utf8_general_ci',
        });
    }

    static associate(db) {
        db.Section.hasMany(db.Team, { 
            foreignKey : "sectionID",
            sourceKey : 'id' 
        });

        db.Section.belongsTo(db.Squad, { 
            foreignKey : "squadID",
            targetKey : 'id' 
        });

    };

}

model/squad.js

const Sequelize = require("sequelize");

module.exports = class Squad extends Sequelize.Model{
    static init(sequelize) {
        return super.init({
            name : {
                type : Sequelize.STRING(20), //STING == MySQL VARCHAR
                allowNull : false, // allowNull == MySQL NOT NULL
                unique : true, // unique == UNIQUE
            },
            created_at : {
                type : Sequelize.DATE, // DATE == MySQL DATETIME
                allowNull : false,
                defaultValue : Sequelize.NOW, // defaultValue == MySQL DEFAULT / Sequelize.NOW == now()
            },   // should you want ZEROFILL option, use [INTERGER.UNSIGNED].ZEROFILL
        },{
            sequelize, //connect with model/index.js
            timestamps : false,
            underscored : false, // createdAt => craeted_at
            modelName : 'Squad',
            tableName : 'squads',
            paranoid : 'false', // if is true, deletedAt column will be craeted. 
            charset : 'utf8', 
            collate : 'utf8_general_ci',
        });
    }

    static associate(db) {
        db.Squad.hasMany(db.Section, { 
            foreignKey : "squadID",
            sourceKey : 'id' 
        });


        db.Squad.hasMany(db.Team, { 
            foreignKey : "squadID",
            sourceKey : 'id' 
        });
    };
    
}

[ Questions ]

Although I know only few things, I am pretty sure that each static associate(db){} has no code mistakes.

But I am not sure whether a table can have belongsTo more than two.

And I am very curious if I can use belongsToMany instead of belongsTo.

How can I solve this error?

Please, I need help :(


Solution

  • You missed db.Squad = Squad; line in index.js:

    db.Team = Team;
    db.Section = Section;
    db.Squad = Squad; // add this line
    
    Team.init(sequelize);
    Section.init(sequelize);
    Squad.init(sequelize);
    
    Section.associate(db);
    Squad.associate(db);
    Team.associate(db);
    

    That's why at this line

    db.Section.belongsTo(db.Squad, { 
                foreignKey : "squadID",
                targetKey : 'id' 
            });
    

    you passed undefined as db.Squad