Sequelize associations hasOne, belongsTo

Problem

The problem is that I can not get working the relation hasOne, which does not eager load the state type object.

All the queries are done on existing tables.

Here is the customer table, whats important is the cst_state_type field:

module.exports = function(sequelize, DataTypes) {

    return sequelize.define('customer', {

        customer: {
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true,
            allowNull: true,
            validate: {
                isNumeric: true
            }
        },
        first_name: {
            type: DataTypes.STRING(100),
            validate: {
                isAlphanumeric: true
            }
        },
        last_name: DataTypes.STRING(100),
        identity_code: {
            type: DataTypes.STRING(20),
            allowNull: true,
            validate: {
                isNumeric: true
            }
        },
        note: DataTypes.STRING(1000),
        birth_date: DataTypes.DATE,


        created_by: DataTypes.INTEGER,
        updated_by: DataTypes.INTEGER,

        cst_type: DataTypes.INTEGER,
        cst_state_type:  {
            type: DataTypes.INTEGER,
        }

    }, {
        tableName: 'customer',

        updatedAt: 'updated',
        createdAt: 'created',
        timestamps: true
    });
};

cst_state_type table:

module.exports = function(sequelize, DataTypes) {

    return sequelize.define('StateType', {

        cst_state_type: {
            type: DataTypes.INTEGER,
            primaryKey: true,
            autoIncrement: true,
            validate: {
            }
        },
        name: DataTypes.STRING(100),
    }, {
        tableName: 'cst_state_type',
        timestamps: false
    });
};

How the relations are described:

  global.db.Customer.hasOne(global.db.StateType, {
    foreignKey: 'cst_state_type',
    as: 'state_type'
  });

  global.db.StateType.belongsTo(global.db.Customer, {
    foreignKey: 'cst_state_type'
  });

And creating eager loading query:

    db.Customer.findAll( {
        include: [
            { model: db.Address, as: 'addresses' },
            { model: db.StateType, as: 'state_type' }
        ]
    })
        .success(function (customers) {
            res.json(200, customers);
        })
        .fail(function (error) {
            res.json(500, { msg: error });
        });
Problem courtesy of: Risto Novik

Solution

I'm pretty sure that the error is in your associations somewhere. From the way you described your table structure, the assocations should look something like this:

global.db.Customer.belongsTo(global.db.StateType, {
    foreignKey: 'cst_state_type',
    as: 'state_type'
});

global.db.StateType.hasMany(global.db.Customer, {
    foreignKey: 'cst_state_type'
});

As i understand it, the same state can be assigned to many customers, therefore StateType.hasMany. The relation from customer -> statetype is a "back-assocation", meaning that the foreign key is in the customer table. For that you need belongsTo

Solution courtesy of: Jan Aagaard Meier

Discussion

Thanks for you answer, it helped me a lot. You can also add the relations directly in your model by using classmethods. I added a example below, hope this helps!

User Model (file)

module.exports = function(sequelize, DataTypes){
    var User = sequelize.define(
        'User', {
            name: {
                type: DataTypes.STRING,
                allowNull: false
            }
        },
        {
            classMethods:{
                associate:function(models){
                    User.hasMany(models.Comment, { foreignKey: 'userId'} );
                }
            }
        }

    );
    return User;
};

Comment Model (file):

module.exports = function(sequelize, DataTypes){
    var Comment = sequelize.define(
        'Comment', {
            text: {
                type: DataTypes.STRING,
                allowNull: false
            }
        },
        {
            classMethods:{
                associate:function(models){
                    Comment.belongsTo(models.User, { foreignKey:'userId'} );
                }
            }
        }

    );
    return Comment;
};

You don't have to set the foreignkey, sequelize will handle it if you don't specify the foreignkeys.

Then in the query:

models.Comment.find({
        where: { id: id },
        include: [
            models.User
        ],
        limit: 1
    })
Discussion courtesy of: Gerard

This recipe can be found in it's original form on Stack Over Flow.