express-rest-api-boilerplate icon indicating copy to clipboard operation
express-rest-api-boilerplate copied to clipboard

How to defined relations among the models

Open anjil opened this issue 5 years ago • 4 comments

@ace3 / @aichbauer can you help me how can I setup the 1:1, 1:N relations in this setup. I am not able to do it and getting error. Please help.

anjil avatar Jul 13 '19 08:07 anjil

Hi, could you provide your error and if possible an example of your app ?

This project uses Sequelize to manage the database. You can find the documentation here ;

Here's an example of a relationship between project and User, where each user has a project (and hence a ForeignKey to Project);

If you wanted a FK from Project to User you would do

Project.hasOne(User)

and if you wanted ManyToMany relationship you would to

Project.hasMany(User)

Here's an extract from the doc

class User extends Model {}
User.init({
  name: Sequelize.STRING,
  email: Sequelize.STRING
}, {
  sequelize,
  modelName: 'user'
});

class Project extends Model {}
Project.init({
  name: Sequelize.STRING
}, {
  sequelize,
  modelName: 'project'
});

User.hasOne(Project);

Hope this helps, if you still have an error please provide it ;)

krzepah avatar Jul 13 '19 10:07 krzepah

@krzepah I am sorry that I didn't gave a relative code here. So I have 2 models namely States.js and UserStates.js

States.js code is

const Sequelize = require('sequelize');
const sequelize = require('../../../config/database');

const UserState = require('./UserState');

const tableName = 'tblstate';

const States = sequelize.define('States', {
  StateID: {
    type: Sequelize.INTEGER(10), 
    primaryKey: true,
    autoIncrement: true
  },
  StateCode: {
    type: Sequelize.ENUM,
    values: ['1', '2', '3', '4', '5']
  },
  Language: {
    type: Sequelize.STRING(10)
  },
  StateDescription: {
    type: Sequelize.TEXT()
  }
}, {
  tableName,
  timestamps: false
});

States.associate = (models) => {
  States.hasOne(models.UserState, {
    foreignKey: StateCode,
    targetKey: StateCode
  });
};

module.exports = States;

and UserStates.js is

const Sequelize = require('sequelize');
const sequelize = require('../../../config/database');
const States = require('./States');

const tableName = 'tbluserstate';

const UserState = sequelize.define('UserState', {
  UserStateID: {
    type: Sequelize.INTEGER(10), 
    primaryKey: true,
    autoIncrement: true
  },
  UserID: {
    type: Sequelize.INTEGER(10)
  },
  StateCode: {
    type: Sequelize.INTEGER(10)
  }
}, {
  tableName,
  timestamps: false
});

UserState.associate = (models) => {
  UserState.belongsTo(models.States, {
    foreignKey: StateCode,
    targetKey: StateCode
  });
};

module.exports = UserState;

In Controller file i am querying as below

let userState = await UserState.findOne({
            include: [State],
            where: {
                UserID: user_id
            }
        });

The error is

(node:10776) UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: States is not associated to UserState!

anjil avatar Jul 13 '19 14:07 anjil

I don't see any part of the doc that specify the usage of .associate, maybe i'm wrong and someone could correct me up;

If I understand your problem properly I would go with something along the line of

States.hasOne(models.UserState, {
  foreignKey: StateCode,
  targetKey: StateCode
});

Instead of

States.associate = (models) => {
  States.hasOne(models.UserState, {
    foreignKey: StateCode,
    targetKey: StateCode
  });
};

This stackoverflow question might hint that the behaviour was depreciated but I cannot find any note about it in the release-notes ;

I couldn't really track down any more intel regarding usage of .associate ; please try without it :)

krzepah avatar Jul 13 '19 15:07 krzepah

hi @anjil ,

can you try to change the code in controller into this

let userState = await UserState.findOne({ include: [States], where: { UserID: user_id } });

since you using States, not State.

ace3 avatar Jul 14 '19 01:07 ace3