尝试以多对多关系创建一个实例和多个相关实例 [英] Trying to create an instance and multiple related instances in a many to many relationship

查看:74
本文介绍了尝试以多对多关系创建一个实例和多个相关实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用联结表创建一个具有多对多关系的实例和多个相关实例。

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.

基本上,我需要创建一个配方。创建完成后,我需要创建成分并将它们与该配方相关联。成分存储在HTML页面上来自表单的数组中。在关联成分时,我需要将 recipient_quantity添加到RecipeIngredients表中,该表是关系的贯穿部分(连接表)。

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

任何帮助将不胜感激。我知道我因为尝试在循环中使用Promise而遇到问题,我只是不知道我还能怎么做到这一点。

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.

推荐答案

我能够解决自己遇到的问题。答案此处有助于我提出我的解决方案。
如果有人遇到类似问题,我将在下面发布解决方案。我创建了一个变量来存储来自Recipe.create()的Promise,我使用Promise.map从表单数据中查找或创建所有成分。因为 findOrCreate 返回包含以下内容的数组Promise和一个布尔值(如果已创建该项目),然后我必须从Promise.map函数的结果中获取实际成分。因此,我使用了JavaScript array.map()函数来从数组中获取第一项。最后,再次使用Promise.map将每种成分添加到配方中

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

这篇关于尝试以多对多关系创建一个实例和多个相关实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆