Cooking recipes app

Yes this is similar, except there is an additional id field on ingredient (like “carrot”). And yes here the quantity is a weight for simplification. I was not very clear in my use case:

  • One user has, say, 2g of carrots and 3g of salad. He wants a recipe that use the most of his stock.
  • So he sends to the API a list of tuples [("carrot", 2), ("salad", 3)].
  • The API should send back a list of recipes names sorted by the “score” value computed with the above algo in pseudocode (the score is a coefficient indicating the pertinence of the recipe with regard to the user ingredients)

My problem does not concern the design of the query (even if I am a newcomer in DQL). For example, I think the previous example could be queried this way (still didn’t validate it though):

{ 
  var(func: eq(Ingredient.id, "carrot")) { carrotId as uid }
  var(func: eq(Ingredient.id, "salad")) { saladId as uid }
  
  var(func: type(Recipe)) {
    recipesIds as uid
    nbValids as count(Recipe.ingredientsWithQuantity @filter(
      	 (uid_in(IngredientWithQuantity.ingredient, uid(carrotId))) AND le(IngredientWithQuantity.quantity, 2)
    	OR (uid_in(IngredientWithQuantity.ingredient, uid(saladId))) AND le(IngredientWithQuantity.quantity, 3)
    ))
  }
        
  var(func: uid(recipesIds)) {
    nbTotal as count(Recipe.ingredientsWithQuantity)
    score as math((nbValids * 1.) / nbTotal) // * 1. because I don't know how to cast to float
  }
  
  me(func: uid(score), orderdesc: val(score)) {
    name: Recipe.name
    score: val(score)
  }
}

My real problem is that the list of user ingredients is dynamic with a size N. I don’t know how to modifiy the above code to work with that. In Cypher and AQL, there is a way to pass list of object as parameters.

But thanks to @verneleem suggestion, I just set a lambda server and now I am able to build the query string with a JS template string without using parameters, like:

{
  ${ constraints.map(({ ingredient }) => `var(func: eq(Ingredient.id, "${ ingredient.name }")) { ${ ingredient.name }Id as uid }`).join('\n') }
  
  var(func: type(Recipe)) {
    recipesIds as uid
    nbValids as count(Recipe.ingredientsWithQuantity @filter(
      	 ${ constraints.map(({ ingredient, quantity }) =>
            uid_in(IngredientWithQuantity.ingredient, uid(${ ingredient.name }Id))) AND le(IngredientWithQuantity.quantity, ${ quantity })`).join(' OR ') }
    ))
  }
  ...
}

And now I can send a list of constraints [("carrot", 2), ("salad", 3)] to the API. I expect I am more clear now :slight_smile:. Is this the way to settle things ? Or is there a full DQL-way to do this ?

Thank you for your time !

1 Like