If any of you have a few minutes, I’d really appre...
# orm-help
d
If any of you have a few minutes, I’d really appreciate some help with an issue I’m having. Details a few posts up. I don’t like keep asking but I’m out of ideas now and I’ve tried here multiple times as well as the forum. I’ve loved learning Prisma so far and I’ve made a lot of progress but this has me stuck. 😕
l
You need an intermediate type to also store the quantity
d
Thanks for the reply! Yeah, an “in between” type was suggested. Is there any documentation or examples of this anywhere? I’m still new to Prisma and GraphQL so learning as I’m going. I get the idea of this extra type in theory but I don’t know how to implement it (which relations and how this’d look in the createRecipe mutation.
l
Are you coming from an SQL background?
d
No, not really. More front-end.
l
Ok, well that's good. It was going to change my answer. 🙂 ...
d
I originally asked my question here and got one reply also mentioning some in-between type. https://www.prisma.io/forum/t/looking-for-help-with-relations-in-my-schema/3886/4
l
Ok let me read it real quickly
d
Thanks!
l
I'm always excited when I give the same answer as Nilan. 🙂 In your second to last post, your schema looks correct but you're still confused about it. Are you confused how to implement it in the resolvers?
🙂 1
d
Yeah, exactly.
My comments here in #general explain the part I don’t get.
Related to the create, etc.
l
Ok, so the
create
vs
connect
just means if the type already exists. So if there's a "salt" ingredient already existing, you connect to it rather than create it.
Are you ok with that part
d
Got it, yeah.
l
So in your business logic, would you be connecting or creating recipes to ingredients?
d
So, as a little background, there’ll be each Ingredient already saved. I have a finite set of ingredients that are re-used across multiple recipes so it made sense to store each separately so we didn’t need to manually add all information for an ingredient each time it was used. Then, when creating a recipe, you can say you want 2 of a certain ingredient. As that ingredient has a default serving size and nutritional information for that serving size, you can calculate the numbers. In the createRecipe I query for each ingredient and then reduce the values (energy, fat, etc.) and create a nutrition object on the final recipe.
Does that make sense?
l
Perfect sense
d
I might as well just show you the mutation now to make it as clear as possible. 🙂
Copy code
createRecipe: async (
    _,
    { ingredients, name, instructions, categories, imageUrl },
    context: Context,
    info
  ) => {
    const ingredientsNutrition = await context.prisma.query.ingredients(
      {
        where: { name: ingredients.name }
      },
      `
      {
        nutrition {
          carbohydrates
          energy
          fat
          protein
        }
      }
      `
    );

    const nutrition: Nutrition = ingredientsNutrition
      .map(ingredient => ingredient.nutrition)
      .reduce((a, b) => {
        return {
          energy: a.energy + b.energy,
          fat: a.fat + b.fat,
          carbohydrates: a.carbohydrates + b.carbohydrates,
          protein: a.protein + b.protein
        };
      });

    return context.prisma.mutation.createRecipe(
      {
        data: {
          name,
          instructions: {
            set: instructions
          },
          categories: {
            connect: [...categories]
          },
          imageUrl: imageUrl,
          nutrition: {
            create: nutrition
          }
        }
      },
      info
    );
  }
l
So working through your question, it looks like the crux of the problem is your mutation formation?
ah.. we're converging 🙂
d
🙂
Yeah, the mutation formation is a problem.
l
So in your
createRecipe
, you don't have any
IngredientInRecipe
d
As you can see in the mutation I shared, I just set categories using connect by just spreading the list of categories (strings). That’s fine but when creating the ingredients, it needs to be an array of objects (ingredients) and each has the quantity and a connection to an actual ingredient.
l
Here's how I'd do it...
Copy code
return context.prisma.mutation.createRecipe(
      {
        data: {
          ...
           ingredients: {
                create: { 
                     quantity: x,
                     recipe: {
                         connect: { id: recipeId }
                     },
                     ingredients: {
                          connect: [{id: id1}, {id: id2}...]
                     }
                     // or if there's only one ingredient per type
                    ingredient: { connect: { id: ingredientId }} 
                }
           }
          ...
        }
      },
      info
    );
  }
Oops.. still working on it
d
🙂
No worries.
l
Ok see if that makes any sense
d
Where do I get the value for the quantity? In the mutation, I’ll have args.ingredients but it’ll be an array like this:
Copy code
[ { quantity: 1, name: 'Rolled Oats' },
  { quantity: 3, name: 'Oat Milk' } ]
It seems like I somehow need to loop over these and create and object in ingredients for each.
Because it’s a quantity of each ingredient.
l
You're going to need the quantity, however derived, the applicable recipe ID, and the ingredient IDs
d
The name in each object in that array is used to query for an ingredient. I then use its info to build the total nutrition object but I still need to save a list of each ingredient and the quantity of it in the recipe.
Copy code
{
  "data": {
    "recipes": [
      {
        "name": "Recipe 1",
        "ingredients": [
          {
            "quantity": 1,
            "ingredient": {
              "name": "Rolled Oats",
              ... // more about that ingredient if I want it
            } 
          },
          {
            "quantity": 3,
            "ingredient": {
              "name": "Oat Milk",
              ... // more about that ingredient if I want it
            } 
          }
        ],
        "nutrition": {
          "fat": 7.5,
          "carbohydrates": 75.7,
          "protein": 14,
          "energy": 427
        }
      }
    ]
  }
}
Please tell me if you think I’m approaching this wrong.
l
In your forum schema,
IngredientInRecipe
had
ingredients
plural, as a list. So that's how I wrote the mutation. Your example return here is as a single object, which makes more sense
How you get the data to perform the mutation Prisma requires is beyond the scope of any outsider's knowledge. That's a product of how you architect everything. But the mutation I wrote above (with the exception of the ingredients list) is how you need to get your data.
The
createRecipe
mutation above will give you the exact output you want
d
That’s good to know. Thanks. How, though, should I derive the quantity where you put x? I haven’t quite grasped that – args.ingredients is an array so to get an individual quantity I’d have to choose an index in the array and that obviously doesn’t make sense.
l
That's going to be an architectural problem. However you get the array, I'd have the ingredient ID with it and then iterate
d
But is it possible to pass multiple values like that to the mutation? I get how to get the values out of the args, that’s fine.
Copy code
ingredients: {
  create: {
    quantity: x, ← 1
    recipe: {
      connect: { id: recipeId }
    },
    ingredients: {
      connect: [
        {id: id1}, ← 2
        {id: id2} ← 3
      ]
    }
  }
}
1) I can’t hard-code a single quantity here. This create essentially needs to be run for each item in the args.ingredients. I don’t know how it works, hence the question. 🙂
l
Copy code
ingredients: [ ... someArray(x => ({
     create: {
              quantity: x.quantity, recipe: { connect: { id: recipeId }}, ingredient: { connect: { x.id }}
     }
 }))]
d
Ah.
I didn’t know I could manipulate the data right there in the mutation.
l
Sure, it's just javascript
d
That’s the missing link for me, I think.
Then in that case, I’ll be able to figure it out. Getting that data in the right shape isn’t a problem; I just thought I had to only pass one create.
l
I may be wrong on the syntax (I always forget where the arrays go with create/connect), but the idea will work
👍 1
d
So that’s why I didn’t know how I’d specify which quantity.
Does that make sense?
l
Are you using Graphql Playground?
d
Yeah.
l
So you can see there the array around create's payload
d
Ah, yeah.
l
So in my schema there, I could create multiple addresses for each deal using the same pattern we just did
d
Got it. Cool.
👍 1
So in my case, when defining the shape of ingredients in the mutation, I can just build a bunch of ingredients (objects) in the right shape, each with their connect to the ingredient itself, etc.
l
Exactly
d
Awesome. Thank you so much. That’s exactly the missing part. Man, 3 days on this! 😑
I really appreciate all the time you’ve given to this.
l
We've all been there. And sadly, will all be there again. 🤣 This stuff isn't easy and the learning curve is steep, but so worth it in the end
Not a problem. Good luck with it!
👍 1
d
Yeah, totally. I love it so far.
Thanks again, man. Have a great day!
l
You too!
n
That's a great discussion! Thanks you two 🙌
@Darryl could you try to summarize your findings in the Forum? This would be a great help for others as well!
d
Thanks, @nilan. Yeah, sure. I’ve made a note and I’ll do that as soon as I get chance.
👌 1
n
great! 🙂
Thanks a lot for the update, @Darryl 🙏
👍 1