hasMany called with something that's not an instance of Sequelize.Model

Viewed 43690

as you guys can see my issue is related to the title description, i created a User Model, and a Foto Model in sequelize, basicly a user can shoot many fotos, but each foto can be related to just 1 user.

My User model

    "use strict";
var sequelize = require('./index');
var bcrypt = require('bcrypt-nodejs');
var Foto = require('./Foto');

module.exports = function (sequelize, DataTypes) {
  var User = sequelize.define("User", {
    username: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
      validate: {
        isUnique: function (value, next) {
          var self = this;
          User.find({ where: { username: value } })
            .then(function (user) {
              // reject if a different user wants to use the same username
              if (user && self.id !== user.id) {
                return next('username already in use!');
              }
              return next();
            })
            .catch(function (err) {
              return next(err);
            });
        }
      }
    },

    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
      validate: {
        isUnique: function (value, next) {
          var self = this;
          User.find({ where: { email: value } })
            .then(function (user) {
              // reject if a different user wants to use the same email
              if (user && self.id !== user.id) {
                return next('Email already in use!');
              }
              return next();
            })
            .catch(function (err) {
              return next(err);
            });
        }
      }
    },

    typeOfUser: {
      type: DataTypes.INTEGER,
      allowNull:true,
      defaultValue:null
    },

    country: {
      type: DataTypes.STRING,
      allowNull:true,
      defaultValue:null
    },

    birthDate:{
      type: DataTypes.DATEONLY,
      allowNull:true,
      defaultValue:null
    },

    reports: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    },

    points: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    },

    password: {
      type: DataTypes.STRING,
      allowNull:false
    },

    numberFotos: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    }
  }, {
      classMethods: {
        generateHash: function (password) {
          return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
        },

      },
      instanceMethods: {
        validPassword: function (password) {
          return bcrypt.compareSync(password, this.password);
        }
      }


    });

  User.hasMany(Foto,{as: 'fotos', foreignKey: 'userId'})

  return Foto;
}

My foto model

"use strict";
var sequelize = require('./index');
var bcrypt = require('bcrypt-nodejs');
var User = require('./User');


module.exports = function (sequelize, DataTypes) {
  var Foto = sequelize.define("Foto", {
    reports: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    },
    image: {
      type: DataTypes.STRING,
      allowNull: false
    },
    date: {
      type: DataTypes.DATE,
      allowNull:true
    },
    position: {
      type: DataTypes.RANGE,
      allowNull: true
    }
  });

  Foto.belongsTo(User, {foreignKey: 'userId'});

  return Foto;
}
8 Answers

You can define relations for both models in one file. It doesn't throw any errors that way.

In your Foto.js, you can try:

...

Foto.belongsTo(User);
User.hasMany(Foto);

return Foto;

I had a similar problem. Sometimes it can be caused because in your index.js or app.js the files are loaded in a specific order, so for example if you have a relationship between A and B, A loads first and references B, and B in turn references A, the error will be thrown inside the B file because A has not been fully defined/executed yet.

The solution to this would be to remove all associations from the model files, and inside your app or index.js require them all, and then define their relationships.

Example

const entities = {
  A: require('./src/Entity/A'),
  B: require('./src/Entity/B'),
};
entities.A.belongsToMany(entities.B, {through: 'AB'});
entities.B.belongsToMany(entities.A, {through: 'AB'});

So I was getting this error and it took me some time to deal with the bug. I realised I was getting the Error because I was referencing the model wrongly. Sequelize is case sensitive so if you created the model with UpperCase ensure to keep it uniform throughout your referencing.

I would also point out you could try this out instead

 User.hasMany(models.Foto ,{as: 'fotos', foreignKey: 'userId'})

It seems you need to define both ends of the relationship in the file containing the 1 part of the 1:many association. That is, the "User" file in your case.

So:

User.hasMany(Foto); Foto.belongsTo(User);

I had lots of issues, but I switched to using the sequelize CLI which generated models in this format, I then found creating associations a lot easier as the index file took care of everything and the static associate({ PersonalDetail }) that is in the model itself already requires your models in one place all you need to do is deconstruct them, so no need to require anything at the top of the file.

This youtube video really helped me out... https://www.youtube.com/watch?v=3qlnR9hK-lQ

'use strict'
const { Model } = require('sequelize')
module.exports = (sequelize, DataTypes) => {
  class User extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate({ PersonalDetail }) {
      // define association here
      this.hasMany(PersonalDetail, {
        foreignKey: 'userId',
        //as: 'personalDetails',
      })
    }
  }
  User.init(
    {
      uuid: {
        type: DataTypes.UUID,
        defaultValue: DataTypes.UUIDV4,
      },
  
      moredata below: {
        type: DataTypes.STRING,
        allowNull: false,
      },

      //createdAt/updatedAt is defined in migration and updated automatically
    },
    {
      sequelize,
      tableName: 'users',
      modelName: 'User',
    }
  )
  return User
}

I got the same type issue. All mappings were done perfectly as explained in the document. Yet, I received the issue regarding the association.

Reason is given by Dorian in this forum.
https://stackoverflow.com/a/60760296/16790144

My approach:

models/company.js

const company = sequelize.define("company",{
  id: {
    type: DataTypes.INTEGER,
    autoIncrement: true,
    primaryKey: true,
  },
  companyName: {
    type: DataTypes.STRING,
    allowNull: false,
  }
});

export default company;

models/client.js

const Client = sequelize.define("client", {
  id: {
    type: DataTypes.INTEGER,
    autoIncrement: true,
    primaryKey: true,
  },
  firstName: {
    type: DataTypes.STRING,
    allowNull: false,
  } 
});

export default Client;

models/clientCompany.js

const clientCompany = sequelize.define("client_company",{
  id: {
    type: DataTypes.INTEGER,
    autoIncrement: true,
    primaryKey: true,
  },
  companyId: {
    type: DataTypes.INTEGER
  },
  clientId: {
    type: DataTypes.INTEGER
  }
});

export default clientCompany;

models/index.js

import Company from './company';
import Client from './client';
import ClientCompany from './clientCompany';

Company.belongsToMany(Client, { through : ClientCompany });
Client.belongsToMany(Company, { through : ClientCompany });

export {
  Company,
  Client,
  ClientCompany,
};

handler.js This file contains the business logic.

import { Client, Company } from '../../models';

const company = await Company.findOne({
  where: { id: companyId },
  include: Client,
});
Related