0
votes

Please suggest a more informative title to this question.

I want to match a recipe based on a provided array of ingredients. If i provide the array ['tomato', celery], I want to match all recipes which has an ingredient whose name contains 'tomato' AND has an ingredient whose name contains 'celery'.

Today I use the following query:

MATCH (recipe:Recipe)
WHERE ALL(
  ingredient IN ['tomato', 'celery']
  WHERE (recipe)-[:CONTAINS_INGREDIENT]->(:Ingredient {name: ingredient})
)
RETURN recipe

This works, provided that the ingredients name is an exact match, but I would like it to match as long as the ingredient name CONTAINS the passed term (i.e. 'Yellow Tomatoes' would match 'tomato'), but I don't see any way to incorporate the CONTAIN keyword into this query.

Is what I'm trying to do possible?

1

1 Answers

1
votes

I believe the most compact way to express this query is using a pattern comprehension and a list comprehension:

WITH ['tomato', 'celery'] AS requiredIngredients
MATCH (recipe:Recipe)
WITH
  recipe,
  size([
    (recipe)-[:CONTAINS_INGREDIENT]->(ingredient:Ingredient)
    WHERE size([requiredIngredient IN requiredIngredients WHERE ingredient.name CONTAINS requiredIngredient]) > 0
    | ingredient]
    ) AS containedRequiredIngredients,
  size(requiredIngredients) AS allRequiredIngredients
WHERE containedRequiredIngredients = allRequiredIngredients
RETURN recipe

The idea is to count the required ingredients (allRequiredIngredients) and the ones that were contained in the recipe (containedRequiredIngredients). If the two values are equal, the recipe is returned.

It can be tested with this example:

CREATE
  (r1:Recipe),
  (r1)-[:CONTAINS_INGREDIENT]->(:Ingredient {name: '50g celery (chopped)'}),
  (r1)-[:CONTAINS_INGREDIENT]->(:Ingredient {name: 'some tomato'})