Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

On sequelize, "include" of "findOne" not working

I made a simple test that is to search for an address (id = 4) and retrieve the user who is linked to that address.

Here are my Models:

user.js

module.exports = function(sequelize, DataTypes) {
    return sequelize.define('User', {
        id: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            field: 'id',
            //primaryKey: true,
        },
        name: {
            type: DataTypes.STRING,
            allowNull: false,
            field: 'name',
        },
    }, {
        freezeTableName: true,
        tableName: 'user',
        createdAt: false,
        updatedAt: false,
        classMethods: {
            associate: function(models) {
                models.User.hasMany(models.UserAddress, { foreignKey: 'userId' });
            },
        },
    });
};

user_address.js

module.exports = function(sequelize, DataTypes) {
    return sequelize.define('UserAddress', {
        id: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            field: 'id',
        },
        userId: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            field: 'user_id',
        },
        title: {
            type: DataTypes.STRING,
            allowNull: true,
            field: 'title',
        },
        address: {
            type: DataTypes.STRING,
            allowNull: true,
            field: 'address',
        },
    }, {
        freezeTableName: true,
        tableName: 'user_address',
        createdAt: false,
        updatedAt: false,
        classMethods: {
            associate: function(models) {
                models.UserAddress.hasOne(models.User, { foreignKey: 'id' });
            },
        },
    });
};

And here is my test file:

db.UserAddress.findOne({
    where: { id: 4 },
    include: [db.User],
}).then(function(address) {
    console.log('------------------------------ Address by "include"');
    console.log('Address title: '+address.title);
    console.log('User id: '+address.userId);
    if(address.User !== null) {
        console.log('User name: '+address.User.name);
    } else {
        console.log('User name: NO USER');
    }

    console.log('');
    address.getUser().then(function(user) {
        console.log('------------------------------ Address by "getUser"');
        console.log('Address title: '+address.title);
        console.log('User id: '+address.userId);
        if(user !== null) {
            console.log('User name: '+address.user.name);
        } else {
            console.log('User name: NO USER');
        }
        console.log('');
    });
});

I do a query with two tests:

  • The first aims to recover the user directly via the variable "user", so thanks to "include" of the request.
  • And the other also retrieve the user but this time via "getUser()".

Here is the result:

$ node test.js
Executing (default): SELECT `UserAddress`.`id`, `UserAddress`.`user_id` AS `userId`, `UserAddress`.`title`, `UserAddress`.`address`, `User`.`id` AS `User.id`, `User`.`name` AS `User.name` FROM `user_address` AS `UserAddress` LEFT OUTER JOIN `user` AS `User` ON `UserAddress`.`id` = `User`.`id` WHERE `UserAddress`.`id`=4;
------------------------------ Address by "include"
Address title: Test
User id: 3
User name: NO USER

Executing (default): SELECT `id`, `name` FROM `user` AS `User` WHERE (`User`.`id`=4);
------------------------------ Address by "getUser"
Address title: Test
User id: 3
User name: NO USER

One can observe that it is impossible to retrieve the result via "include" and "getUser()". The error is visible in the log of SQL:

"include": LEFT OUTER JOIN `user` AS `User` ON `UserAddress`.`id` = `User`.`id`
and
"getUser()": SELECT `id`, `name` FROM `user` AS `User` WHERE (`User`.`id`=4);

While the correct answer should have been:

"include": LEFT OUTER JOIN `user` AS `User` ON `UserAddress`.`user_id` = `User`.`id`
and
"getUser()": SELECT `id`, `name` FROM `user` AS `User` WHERE (`User`.`id`=3);

So my question is, what is the configuration to put in my Model or my request for the result to be correct with "include" and "getUser()" ?

Thank you.

(Also posted on: https://github.com/sequelize/sequelize/issues/3182)

like image 888
SiteXw Avatar asked Feb 20 '15 12:02

SiteXw


People also ask

How does include work in Sequelize?

To wrap up, include takes an array of objects. These objects are queries of their own, essentially just Sequelize queries within our main query. Inside each include query we specify the associated model , narrow our results with where , and alias our returned rows with as .

How do I add a foreign key to Sequelize?

Sequelize association methods also accept an options object that you can use to configure the details of the association. For example, you can change the foreign key name on the table by adding the foreignKey property: User. hasOne(Invoice, { foreignKey: "invoice_creator", // UserId -> invoice_creator });


1 Answers

Answer from the github page - need to use belongsTo instead of hasOne.

user.js

module.exports = function(sequelize, DataTypes) {
    return sequelize.define('User', {
        id: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            field: 'id',
            //primaryKey: true,
        },
        name: {
            type: DataTypes.STRING,
            allowNull: false,
            field: 'name',
        },
    }, {
        freezeTableName: true,
        tableName: 'user',
        createdAt: false,
        updatedAt: false,
        classMethods: {
            associate: function(models) {
                models.User.hasMany(models.UserAddress, { foreignKey: 'userId' });
            },
        },
    });
};

user_address.js

module.exports = function(sequelize, DataTypes) {
    return sequelize.define('UserAddress', {
        id: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            field: 'id',
        },
        userId: {
            type: DataTypes.INTEGER(10).UNSIGNED,
            allowNull: false,
            field: 'user_id',
        },
        title: {
            type: DataTypes.STRING,
            allowNull: true,
            field: 'title',
        },
        address: {
            type: DataTypes.STRING,
            allowNull: true,
            field: 'address',
        },
    }, {
        freezeTableName: true,
        tableName: 'user_address',
        createdAt: false,
        updatedAt: false,
        classMethods: {
            associate: function(models) {
                models.UserAddress.belongsTo(models.User, { foreignKey: 'userId' });
            },
        },
    });
};
like image 195
jjbskir Avatar answered Oct 14 '22 19:10

jjbskir