2

My models:

 Recipe (id, name)
 Ingredient (id, name)
 Recipe_Ingredient (recipeId, ingredientId, quantity)

My associations:

Recipe.belongsToMany(Ingredient, { through: Recipe_Ingredient })
Ingredient.belongsToMany(Recipe, { through: Recipe_Ingredient })

My problem:

How can I create a Recipe with some Ingredients and the quantities attached to them?

I tried:

Recipe.create({
  name: 'Pizza',
  ingredients:[
    {
      name: 'mozarella',
      recipe_ingredients: {
          quantity: 5
      }
    }
  ]
}, {
    include:[Ingredient]
})

Records are created for Recipe, Ingredient and the Recipe_Ingredient. The only problem is that the value of the quantity is not collected from the data source.

Pedro A
  • 3,989
  • 3
  • 32
  • 56
bluehipy
  • 2,254
  • 1
  • 13
  • 19

2 Answers2

1

A solution I found, inspired by answers of pedro around here (How do I ORM additional columns on a join table in sequelize?) and there is given by a change of perspective.

receipe (name:string)
ingredient (quantity:int)
type (name: string)

receipe.hasMany(ingredient, {as:'ingredients'} )
ingredient.belongsTo(type)

and then I can consume data like this:

receipe.create({
  name: 'Pizza',
  ingredients:[
    {
      quantity: 5,
      type: {
         name: 'ingredient 1'
      }
    }, {
      quantity: 6,
      type: {
         name: 'ingredient 2'
      }
    } {
      quantity: 5,
      type_id: 1
    }]
}, {
    include:[{
       model; ingredient,
       as: 'ingredients',
       include:[{
         model: type
       }]
    }]
})

It has some drawbacks but it is good enough for me.

One problem can be that if you add two items of the same new type, you will get a unique key violation (as types are unique and sequelize will not try to search if the type exists before trying to create it).

Another problem is that if you specify just the type_id in the data, it will not actually return the type refereed by that in the result.

bluehipy
  • 2,254
  • 1
  • 13
  • 19
  • Hello! Nice solution. I like the change of perspective you did here. But I also agree with you that it would be better if it just worked in the way you imagined in the first place. By the way, while investigating for other solutions I tested a few things and stumbled in a weird error message in one of my attempts, and opened an issue about it: [#10034](https://github.com/sequelize/sequelize/issues/10034). Let's see :) – Pedro A Oct 15 '18 at 23:53
  • 1
    By the way, in your question you tried `receipe_ingredients: { quantity: 5 }` but to me `receipe_ingredient: { quantity: 5 }` (in singular) makes more sense (although none of them worked anyway). – Pedro A Oct 15 '18 at 23:55
  • Hey @PedroA! Thanks, let s see if there is a solution for that! :) – bluehipy Oct 16 '18 at 08:41
1

It was not possible to do this in the past, but in October 23, 2018 this was fixed in sequelize PR #10050.

As of today (2018-10-24) the fix is not released yet, but as soon as v5.0.0-beta14 comes out, you'll be able to do the following:

Recipe.create({
    name: 'Pizza',
    ingredients: [
        {
            name: 'mozarella',
            recipe_ingredient: {
                quantity: 5
            }
        }
    ]
}, {
    include: Ingredient
})

Also, note that the correct usage is recipe_ingredient: in the singular form, not in the plural form as you tried in your question. This makes sense, because for a given Ingredient, associated with a given Recipe, there is only one Recipe_Ingredient involved, always.

If you do not want to wait for v5.0.0-beta14 (although it will probably be released very soon), you can install it directly from github's master branch as follows:

npm install --save https://github.com/sequelize/sequelize/tarball/master

Pedro A
  • 3,989
  • 3
  • 32
  • 56