user8014710
user8014710

Reputation:

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

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;
}

Upvotes: 17

Views: 55614

Answers (9)

Toufiq
Toufiq

Reputation: 1213

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;

Upvotes: 20

talha
talha

Reputation: 1

I have done following changes and it worked for me

  1. change the exports from this

    const User = sequelize.define( // your model code here )

    module.exports = User

To

exports.User = sequelize.define(
//
)

And then import both models in separate file , and define relation in that seprate file, i named that file as userCollection.js, Here is the code

const { Collection } = require("../models/collection");
const { User } = require("../models/user");


User.hasMany(Collection, { foreignKey: "userId", as:"collections", });
Collection.belongsTo(User, { foreignKey: "userId" })

Upvotes: 0

Didula Lakshitha
Didula Lakshitha

Reputation: 11

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,
});

Upvotes: 1

trig79
trig79

Reputation: 444

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
}

Upvotes: 0

user1653042
user1653042

Reputation: 403

None of the above solutions worked for my scenario (could work for other setups). I stumbled upon this article which states you have to have the models defined and exported prior to applying the associations. Using a separate extra-setup.js file to define the associations, worked for me.

https://github.com/sequelize/express-example/tree/master/express-main-example

Upvotes: 1

muwonge nicholus
muwonge nicholus

Reputation: 144

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'})

Upvotes: 4

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'});

Upvotes: 8

Scar Coder
Scar Coder

Reputation: 397

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);

Upvotes: 1

Ellebkey
Ellebkey

Reputation: 2301

You don't need to declare the association on the Photo Model:

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

When you have a 1:N relation between models you only need to refer the id from the "1" model, on our case the User model, on the "N" model, Photos. So doing:

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

Will create a column on your Foto table with name "userId" that refer to user table. On this way both models are associate as you want.

Upvotes: 45

Related Questions