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


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

If you are using an alias on the association ({ as: 'Food' }) you need to use it on the include statement as well.

So it'd be like that:

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

If an association is aliased (using the as option), you must specify this alias when including the model. Notice how the user's Tools are aliased as Instruments above. In order to get that right you have to specify the model you want to load, as well as the alias

More information here.