Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

155
Visualizações
Trying to create an instance and multiple related instances in a many to many relationship

I am attempting to create an instance and multiple related instances with a many to many relation using a junction table.

While creating the multiple related instances, I need to add a value to a property on the junction table as well. I don't know if it is my lack of knowledge of sequelize or promises that is causing my problem.

The code I am using is below. This code does add the items to the database, but I need to redirect after the operation has completed, which is not working.

Basically, I need to create a Recipe. Once that is created, I need to create Ingredients and relate them to that Recipe. The ingredients are stored in an array coming from a form on an HTML page. While relating the Ingredients, I need to add the ingredient_quantity to the RecipeIngredients table, which is the through part of the relationship (the junction table).

global.db.Recipe.belongsToMany(
    global.db.Ingredient, 
    { 
        as: 'Ingredients', 
        through: global.db.RecipeIngredients, 
        foreignKey: 'recipe_id' 
    });
global.db.Ingredient.belongsToMany(
    global.db.Recipe, 
    { 
        as: 'Recipes', 
        through: global.db.RecipeIngredients, 
        foreignKey: 'ingredient_id' 
    });

router.post('/new', ensureLoggedIn, bodyParser.json(), function (req, res) {
    var recipeName = req.body.recipe_name;
    var steps = req.body.steps;
    var ingredients = req.body.ingredients;
    var ingredientQty = {};
    var currentIngredient;
    var ingredientsToAdd = [];

    db.Recipe.create({
        recipe_name: recipeName,
        directions: steps,
        FamilyId: req.user.FamilyId,
        CreatedBy: req.user._id
    })
    .then(function (recipe) {
        for (var i = 0; i < ingredients.length; i++) {

            currentIngredient = ingredients[i];
            ingredientQty[currentIngredient.ingredient_name] = 
currentIngredient.quantity;

            db.Ingredient.findOrCreate({
                where: { 
                    ingredient_name: currentIngredient.ingredient_name, 
                    FamilyId: req.user.FamilyId 
                }
            })
            .spread(function (ingredient, created) {
                if (created) {
                    console.log("Added Ingredient to DB: " + 
                    currentIngredient.ingredient_name);
                }

            ingredient.Recipes = {
                ingredient_quantity: 
                    ingredientQty[ingredient.ingredient_name]
            };
            ingredient.CreatedBy = req.user._id;
            recipe.addIngredient(ingredient)
            .then(function () {
                console.log("Added Ingredient " + ingredient.ingredient_name 
                + " to Recipe " + recipe.recipe_name);
            });
        })
    }

})
.finally(function(recipe){
    res.redirect('/recipes');
});
});

Any help would be greatly appreciated. I know that I am running into issues because of trying to use promises inside of a loop, I just don't know how else I can accomplish this.

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Using sequelize, you can create objects along with its associated objects in one step, provided all objects that you're creating are new. This is also called nested creation. See this link and scroll down to section titled "Creating with associations"

Coming to your issue, you've a many-to-many relationship between Recipe and Ingredient, with RecipeIngredients being the join table.

Suppose you've a new Recipe object which you want to create, like:

var myRecipe = {
  recipe_name: 'MyRecipe',
  directions: 'Easy peasy',
  FamilyId: 'someId',
  CreatedBy: 'someUserId'
}

And an array of Ingredient objects, like:

var myRecipeIngredients = [
  { ingredient_name: 'ABC', FamilyId: 'someId'},
  { ingredient_name: 'DEF', FamilyId: 'someId'},
  { ingredient_name: 'GHI', FamilyId: 'someId'}]

// associate the 2 to create in 1 step
myRecipe.Ingredients = myRecipeIngredients;

Now, you can create myRecipe and its associated myRecipeIngredients in one step as shown below:

Recipe.create(myRecipe, {include: {model: Ingredient}})
.then(function(createdObjects){
   res.json(createdObjects);
})
.catch(function(err){
   next(err);
});

And that is all !!
Sequelize will create 1 row in Recipe, 3 rows in Ingredient and 3 rows in RecipeIngredients to associate them.

over 4 years ago · Santiago Trujillo Relatório

0

I was able to fix the problem that I was having. The answers here helped me come up with my solution. I am posting the solution below in case anyone else runs into a similar issue. I created a variable to store the Promise from Recipe.create(), I used Promise.map to findOrCreate all of the ingredients from the form data. Because findOrCreate returns an array containing Promise and a boolean for if the item was created, I then had to get the actual ingredients out of the results of the Promise.map function. So I used the JavaScript array.map() function to get the first item from the arrays. And finally, use Promise.map again to add each Ingredient to the Recipe

var ingredients = req.body.ingredients,
    recipeName = req.body.recipeName,
    ingredientsQty = {}; // Used to map the ingredient and quantity for the 
                         // relationship, because of the Junction Table

var recipe = models.Recipe.create({recipe_name: recipeName});

// Use Promise.map to findOrCreate all ingredients from the form data
Promise.map(ingredients, function(ing){
    ingredientsQty[ing.ingredient_name] = ing.ingredient_quantity;
    return models.Ingredient.findOrCreate({ where: { ingredient_name: ing.ingredient_name}});
})

// Use JavaScript's Array.prototype.map function to return the ingredient 
// instance from the array returned by findOrCreate
.then(function(results){
    return results.map(function(result){
        return result[0];
    });
})

// Return the promises for the new Recipe and Ingredients
.then(function(ingredientsInDB){
    return Promise.all([recipe, ingredientsInDB]);
})

// Now I can use Promise.map again to create the relationship between the / 
// Recipe and each Ingredient
.spread(function(addedRecipe, ingredientsToAdd){
    recipe = addedRecipe;
    return Promise.map(ingredientsToAdd, function(ingredientToAdd){
        ingredientToAdd.RecipeIngredients = {
            ingredient_quantity: ingredientsQty[ingredientToAdd.ingredient_name]
        };

        return recipe.addIngredient(ingredientToAdd);
    });
})

// And here, everything is finished
.then(function(recipeWithIngredients){
   res.end
});
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda