Sequelize hasMany Join association

27,705

Solution 1

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

Solution 2

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.

Share:
27,705
leofontes
Author by

leofontes

Undergrad from Florianopolis - Brazil, currently working on mobile software development (Android and iOS) and Web development (NodeJS).

Updated on July 09, 2022

Comments

  • leofontes
    leofontes almost 2 years

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

  • leofontes
    leofontes almost 8 years
    Still gives me the error: Unhandled rejection Error: food (Food) is not associated to meal!
  • leofontes
    leofontes almost 8 years
    Reading the documentation (again), the example makes sense, but I don't think it 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). How can I get around that?
  • oleh.meleshko
    oleh.meleshko almost 8 years
    @leofontes in your situation you need to implement many-to-many relationship, a meal can have many foods, and one food can be used in multiple meals, so that makes sense. Follow documentation to implement this kind of relationship.
  • leofontes
    leofontes almost 8 years
    Excelent! This gave me the result I wanted, just one final question.. I'm printing the JSON.stringify(meals) and it shows every part of the data, but what if I wanted to access some of those values by themselves, how could I do it?
  • Steffen Langer
    Steffen Langer almost 8 years
    Like access each food?
  • Mohit Mutha
    Mohit Mutha over 5 years
    Thanks, I spent a complete day unsuccessfully before I found this answer.