Sequelize hasMany Join association

leofontes picture leofontes · Jun 28, 2016 · Viewed 20.8k times · Source

I'm expanding my application and I need to join two models I had previously created with Sequelize, they are as follows:

Meal

sequelize.define('meal', {
    mealId: {
        type: DataTypes.INTEGER, 
        primaryKey: true,
        autoIncrement: true
    },
    quantity: {
        type: DataTypes.DECIMAL,
        allowNull: false
    },
    period: {
        type: DataTypes.INTEGER,
        allowNull: false
    }
})

Food

sequelize.define('food', {
    idFood: {
        type: DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true
    },
    nameFood: {
        type: DataTypes.STRING,
        allowNull: false
    }
})

I added the following relationship:

db.food.hasMany(db.meal, {as : 'Food', foreignKey : 'idFood'});

This line adds an idFood column on Meal

Quickly explaining what is going on, Food is a table with many foods (duh) like Bread, Rice, Beans, etc. Meal is a table that identifies which food the user has chosen with their details.

Therefore, my understanding was that Meal had many Food (as I added before) but Food didn't require any relationship with Meal, since it just holds data and isn't changed after I first populate it. But when I tried to join them with:

db.meal.findAll({ include : [db.food] }).then(function (meals) {
    console.log(JSON.stringify(meals));
});

I got the following error:

Unhandled rejection Error: food is not associated to meal!

Can anyone explain what I should do? I think it has to do with the relationships, but I couldn't find on the documentation any good explanation as to what I should do.

Thank you!

Edit: Reading the documentation (again), the example makes sense, but I don't think the example is applicable on my situation, because on their example, User has a Task, and Task belongs to User. But on my case, Food doesn't belong to a Meal, because many Meals can have the same Food in different amounts (or for different users).

Answer

Steffen Langer picture Steffen Langer · Jun 28, 2016

The issue is that the relation has to be defined both ways. Currently, Sequelize knows how to get from Food -> Meal because of

db.food.hasMany(db.meal, {as : 'Food', foreignKey : 'idFood'});

but it does not know how to get from Meal -> Food. That's why you have to define the same relation the other way round, like so:

db.meal.belongsTo(db.food, {foreignKey : 'idFood'});

This does not add any new keys since it would define meal.idFood which you defined with your first statement already.

Now you should be able to execute

db.meal.findAll({ include : [db.food] }).then(function (meals) {
    console.log(JSON.stringify(meals)); <-- each array element of meals should have an attribute `food`
});