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 . Is this the way to settle things ? Or is there a full DQL-way to do this ?
Thank you for your time !