1

I'm totally newbie with Sequelize and I'm getting the next error when I run my application and sync my tables:

TypeError: UserModel.hasMany is not a function
    at Object.<anonymous> (/home/josecarlos/Workspace/nodejs/remote-roofing/src/server/models/users.js:46:11)
    at Module._compile (internal/modules/cjs/loader.js:816:30)
    at Module._compile (/home/josecarlos/Workspace/nodejs/remote-roofing/node_modules/pirates/lib/index.js:99:24)
    at Module._extensions..js (internal/modules/cjs/loader.js:827:10)
    at Object.newLoader [as .js] (/home/josecarlos/Workspace/nodejs/remote-roofing/node_modules/pirates/lib/index.js:104:7)

I've got two tables only, so I have defined two models. One for each one and try to relationship between them.

user.js

import ProjectModel from "./projects";

const UserModel = (sequelize, type) => {
    return sequelize.define("user", {
        id: {
            type: type.INTEGER,
            primaryKey: true,
            autoIncrement: true,
            allowNull: false,
        },
        email: {
            type: type.STRING,
            allowNull: false,
            isEmail: {
                msg: "The format of the e-mail is not correct"
            },
            validate: {
                notNull: {
                    msg: "E-mail cannot be empty"
                }
            }
        },
        name: {
            type: type.STRING,
            is: /^[a-zA-Z ]+$/i,
            allowNull: false,
            validate: {
                notNull: {
                    msg: "Name cannot be empty"
                }
            }
        },
        surname: {
            type: type.STRING,
            is: /^[a-zA-Z ]+$/i,
            allowNull: false,
            validate: {
                notNull: {
                    msg: "Surname cannot be empty"
                }
            }
        }
    })
};

UserModel.hasMany(ProjectModel, { foreingKey: "userID", sourceKey: "id"});
ProjectModel.belongsTo(UserModel, { foreingKey: "userID", sourceKey: "id"});

module.exports.UserModel = UserModel;

project.js

import UserModel from "./users";

const ProjectModel = (sequelize, type) => {
    return sequelize.define("project", {
        id: {
            type: type.INTEGER,
            primaryKey: true,
            autoIncrement: true,
            allowNull: false,
        },
        name: {
            type: type.STRING,
            is: /^[a-zA-Z ]+$/i,
            allowNull: false,
            validate: {
                notNull: {
                    msg: "Name cannot be empty"
                }
            }
        },
        body: {
            type: type.TEXT,
            allowNull: false,
            validate: {
                notNull: {
                    msg: "Body cannot be empty"
                }
            }
        },
        status: {
            type: type.ENUM("active", "inactive", "declined", "completed"),
            allowNull: false,
            validate: {
                notNull: {
                    msg: "Status cannot be empty"
                }
            }
        },
        userID: {
            type: type.INTEGER,
            allowNull: false,
            validate: {
                notNull: {
                    msg: "userID cannot be empty"
                }
            }
        }
    })
};

module.exports.ProjectModel = ProjectModel;

This two models are create from db.js:

import Sequelize from "sequelize";
import UserModel from "./models/users";
import ProjectModel from "./models/projects";
//It's mandatory to import dotenv in each file where we can use enviroment variables
import config from "dotenv";
config.config(); 

const sequelize = new Sequelize(process.env.DDBB_NAME, process.env.DDBB_USER,process.env.DDBB_PSWD, {
        host: process.env.DDBB_HOST, 
        port: process.env.DDBB_PORT,
        define: {
            //freezeTableName: true, /**Don't add 's to the end of each table/model */
            //timestamps: false,  /**Don't add fields createdAt and updatedAt */          
        },
        dialect: "postgres",
        pool: {
            max: 5,
            min: 0,
            acquire: 30000,
            idle: 10000
        }
    }
);


const User = UserModel(sequelize, Sequelize);
const Project = ProjectModel(sequelize, Sequelize);

sequelize.sync({force: false}).then(() => {
    console.log("Tables syncronized!!!")
})

module.exports = {
    User,
    Project
};

This file is required when I run the application. And I've got the error that I have showned before.

What am I doing wrong?

Edit I:

I have modified db.js file and it doesn't work to me. I've got the same error. I don't know how been called the models :(((((

import Sequelize from "sequelize";
import UserModel from "./models/users";
import ProjectModel from "./models/projects";
import fs from "fs";
import path from "path";
//It's mandatory to import dotenv in each file where we can use enviroment variables
import config from "dotenv";
config.config(); 

const sequelize = new Sequelize(process.env.DDBB_NAME, process.env.DDBB_USER,process.env.DDBB_PSWD, {
        host: process.env.DDBB_HOST, 
        port: process.env.DDBB_PORT,
        define: {
            //freezeTableName: true, /**Don't add 's to the end of each table/model */
            //timestamps: false,  /**Don't add fields createdAt and updatedAt */          
        },
        dialect: "postgres",
        pool: {
            max: 5,
            min: 0,
            acquire: 30000,
            idle: 10000
        }
    }
);

let db = {
    sequelize,
    Sequelize,
    models: {}
}

//Register Models
const models = path.join(__dirname, "models");
fs
  .readdirSync(models)
  .filter(function (file) {
    return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js')
  })
  .forEach(function (file) {
    var model = sequelize['import'](path.join(models, file))
    db[model.name] = model
  })

Object.keys(db).forEach(function (modelName) {
  if (db[modelName].associate) {
    db[modelName].associate(db)
  }
})


db.sequelize.sync({force: false}).then(() => {
    console.log("Tables syncronized!!!")
})

module.exports.db = db;

Edit II:

Now, I've got this error:

/home/josecarlos/Workspace/nodejs/remote-roofing/src/server/models/users.js:9
var UserModel = _db["default"].sequelize.define("user", {
                                         ^

TypeError: Cannot read property 'define' of undefined
    at Object.<anonymous> (/home/josecarlos/Workspace/nodejs/remote-roofing/src/server/models/users.js:4:32)

db.js

import Sequelize from "sequelize";
import UserModel from "./models/users";
import ProjectModel from "./models/projects";
import fs from "fs";
import path from "path";
//It's mandatory to import dotenv in each file where we can use enviroment variables
import config from "dotenv";
config.config(); 

const sequelize = new Sequelize(process.env.DDBB_NAME, process.env.DDBB_USER,process.env.DDBB_PSWD, {
        host: process.env.DDBB_HOST, 
        port: process.env.DDBB_PORT,
        define: {
            //freezeTableName: true, /**Don't add 's to the end of each table/model */
            //timestamps: false,  /**Don't add fields createdAt and updatedAt */          
        },
        dialect: "postgres",
        pool: {
            max: 5,
            min: 0,
            acquire: 30000,
            idle: 10000
        }
    }
);

let db = {
    sequelize: sequelize,
    Sequelize: Sequelize,
    models: {}
}

//Register Models
const models = path.join(__dirname, "models");
fs
  .readdirSync(models)
  .filter(function (file) {
      console.log("file: " + file);
    return (file.indexOf('.') !== 0) && (file.slice(-3) === '.js')
  })
  .forEach(function (file) {
    var model = sequelize['import'](path.join(models, file))
    db[model.name] = model
  })

Object.keys(db).forEach(function (modelName) {
  if (db[modelName].associate) {
    db[modelName].associate(db)
  }
})


db.sequelize.sync({force: false}).then(() => {
    console.log("Tables syncronized!!!")
})

module.exports.db = db;

users.js

import Sequelize from "sequelize";
import db from "../db";

const UserModel = db.sequelize.define("user", {
    id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true,
        allowNull: false,
    },
    email: {
        type: Sequelize.STRING,
        allowNull: false,
        isEmail: {
            msg: "The format of the e-mail is not correct"
        },
        validate: {
            notNull: {
                msg: "E-mail cannot be empty"
            }
        }
    },
    name: {
        type: Sequelize.STRING,
        is: /^[a-zA-Z ]+$/i,
        allowNull: false,
        validate: {
            notNull: {
                msg: "Name cannot be empty"
            }
        }
    },
    surname: {
        type: Sequelize.STRING,
        is: /^[a-zA-Z ]+$/i,
        allowNull: false,
        validate: {
            notNull: {
                msg: "Surname cannot be empty"
            }
        }
    }
})

UserModel.associate = (models) => {
    UserModel.hasMany(models.ProjectModel, {
        foreignKey: "userID"
    })
}

module.exports.UserModel = UserModel;

project.js

import Sequelize from "sequelize";
import db from "../db";

const ProjectModel = db.sequelize.define("project", {
    id: {
        type: type.INTEGER,
        primaryKey: true,
        autoIncrement: true,
        allowNull: false,
    },
    name: {
        type: type.STRING,
        is: /^[a-zA-Z ]+$/i,
        allowNull: false,
        validate: {
            notNull: {
                msg: "Name cannot be empty"
            }
        }
    },
    body: {
        type: type.TEXT,
        allowNull: false,
        validate: {
            notNull: {
                msg: "Body cannot be empty"
            }
        }
    },
    status: {
        type: type.ENUM("active", "inactive", "declined", "completed"),
        allowNull: false,
        validate: {
            notNull: {
                msg: "Status cannot be empty"
            }
        }
    },
    userID: {
        type: type.INTEGER,
        allowNull: false,
        validate: {
            notNull: {
                msg: "userID cannot be empty"
            }
        }
    }
});


ProjectModel.associate = (models) => {
    ProjectModel.belongsTo(models.UserModel, {
        foreignKey: "userID"
    })
}

module.exports.ProjectModel = ProjectModel;

Sorry, but I don't understand anything ... :((

Edit III:

I have checked the keys of db in user.js and I've got nothing, so it's right that I've got thi error, but ... Why have db nothing?

[nodemon] starting `babel-node src/server/server.js`
db: 
José Carlos
  • 2,850
  • 12
  • 59
  • 95

1 Answers1

0

Your issue is that UserModel in user.js is as a function that returns a sequalize definition.

In the same file you are trying to call UserModel.hasMany on the function that returns your model object instead of on the model object itself.

You probably just want to remove the wrapping function and assign the sequalize object to UserModel directly.

const UserModel = sequelize.define("user", {
...

or move the calls on UserModel into the function.

    const model = sequelize.define("user", {
    ...
    });
    model.hasMany(ProjectModel, { foreingKey: "userID", sourceKey: "id"});
    model.belongsTo(UserModel, { foreingKey: "userID", sourceKey: "id"});
    return model;
};
module.exports.UserModel = UserModel;
Deadron
  • 5,135
  • 1
  • 16
  • 27
  • Thanks @Deadron I have updated my code and I've got still an error. Now is different. I have updated my original post. – José Carlos Jun 02 '20 at 20:46