Cypher查询在查找多个记录时不返回关系

问题描述:

我在写一个查询食谱的查询。我想用匹配查询的食谱返回当前的用户交互(喜欢等)。Cypher查询在查找多个记录时不返回关系

该查询返回正确的当前用户的所有交互:

MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: 'some-id'}) 
RETURN reaction 

然而,当我在比赛添加到现有的搜索查询,该reaction变量是空的每一条记录:

MATCH (recipe:Recipe) 
OPTIONAL MATCH (recipe)-[a:CONTAINS]->(i:Ingredient) 
OPTIONAL MATCH (recipe)-[:IS]->(c:Category) 
OPTIONAL MATCH (recipe)<-[:AUTHORED]-(u:User) 
OPTIONAL MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: 'some-id'}) 
WHERE ALL(
    ingredient IN ['tomato', 'banana'] 
    WHERE (recipe)-[:CONTAINS]->(:Ingredient {name: ingredient}) 
) 
AND ALL(
    category IN ['smoothie'] 
    WHERE (recipe)-[:IS]->(:Category {name: category}) 
) 
RETURN DISTINCT recipe, 
{username: u.username, cuid: u.cuid} AS author, 
{love: reaction.love, favorite: reaction.favourite} AS interactions, 
collect(DISTINCT {name: i.name, amount: a.amount}) AS ingredients, 
collect(DISTINCT {name: c.name}) AS categories 

查询我用来获取单个食谱的ID尽管它应该如此:

MATCH (recipe:Recipe {cuid: {recipeCuid}}) 
OPTIONAL MATCH (recipe)-[a:CONTAINS]->(i:Ingredient) 
OPTIONAL MATCH (recipe)-[:IS]->(c:Category) 
OPTIONAL MATCH (recipe)<-[:AUTHORED]-(u:User) 
OPTIONAL MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: {beholderCuid}}) 
RETURN recipe, 
{username: u.username, cuid: u.cuid} AS author, 
{love: reaction.love, favorite: reaction.favorite} AS interactions, 
collect(DISTINCT {name: i.name, amount: a.amount}) AS ingredients, 
collect(DISTINCT {name: c.name}) AS categories 

任何指向我在做什么错的?

+0

1.如果从查询中删除WHERE子句,结果如何?也许'WHERE'子句过滤掉了'reaction'不为空的所有匹配项。 2.这可能没有什么区别,但在你的第一个查询中,你没有指定'recipe'应该有一个'Recipe'标签。 –

+0

它在我删除where子句时起作用!任何想法,我可以如何使它与'WHERE'子句一起工作? – Amygdaloideum

+0

如果只保留'WHERE'子句中的一个条件,即只检查'ingredient'还是仅检查'category',会发生什么? –

的Gabor的查询是一个很好的一步,因为它移动你的WHERE后WITH而不是与可选MATCH保持它...这是你无法得到正确的结果的主要原因。

但是,查询还需要一些提高效率。对于一个,如果您不立即运行聚合,则连续出现多个MATCH或OPTIONAL MATCH,特别是那些将返回多行(成分,类别)的MATCH或OPTIONAL MATCH会影响剩余MATCH或可选MATCH的效率。例如,对于具有3个成分和2个类别的单一配方,在您的前两个可选匹配完成时排出的是3 x 2 = 6行,这意味着其他可选匹配需要在所有6个配方中执行的行,但你的意图是他们只能为每个配方执行一次,而不是多次。

这就是为什么尽快进行聚合是有用的,因为它可以将每个配方的行数减少到一个,而不是多个(对于配方和配料以及类别的每个组合,配方只有一个配料和一个类别)。

此外,你只过滤下来(基于成分和类别)您在所有剩下的唯一匹配后,意味着你在那肯定会被过滤掉行运行许多可选的匹配。这是浪费工作,浪费分贝点击。尽可能快地做你的过滤,然后在你知道你将要返回的行上运行你需要的额外的可选匹配。

最后,因为你只能似乎想回行与某些成分,只有某些类别的食谱,我们应该用火柴成分和类别,不是可有可无的匹配。

我建议是这样的一种改进的查询:

MATCH (cat:Category) 
WHERE cat.name IN ['smoothie'] 
WITH COLLECT(cat) as desiredCategories 
MATCH (i:Ingredient) 
WHERE i.name IN ['tomato', 'banana'] 
WITH desiredCategories, COLLECT(i) as desiredIngredients 
MATCH (recipe:Recipe) 
WHERE ALL(
    category IN desiredCategories 
    WHERE (recipe)-[:IS]->(category) 
) 
AND ALL(
    ingredient IN desiredIngredients 
    WHERE (recipe)-[:CONTAINS]->(ingredient) 
) 
WITH recipe 
MATCH (recipe)-[:IS]->(c:Category) 
WITH recipe, COLLECT(c) as categories 
MATCH (recipe)-[a:CONTAINS]->(i:Ingredient) 
WITH recipe, categories, COLLECT({name: i.name, amount: a.amount}) as ingredients 
OPTIONAL MATCH (recipe)<-[:AUTHORED]-(u:User) 
// only one author, so okay to use optional matches back to back 
OPTIONAL MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: 'some-id'}) 
RETURN recipe, 
    {username: u.username, cuid: u.cuid} AS author, 
    {love: reaction.love, favorite: reaction.favourite} AS interactions, 
    ingredients, 
    categories 

你应该能够看到,运行我们收集()之后我们做的比赛返回多个行,我们保持建每个配方将每行添加到1个集合(集合是单行,而未收集时是多行)。

你也应该能够看到,因为我们过滤掉没有所需类别或成分的食谱,因此作者和反应的结尾的可选匹配将仅适用于具有所需类别的食谱以及配料,而不是无用的食谱,将被过滤掉。

编辑

我注意到了,晚了,有与你检查类别和成分的方式有问题,你不能在节点直接与您的数组名称进行比较。您可能在以下物料上有name财产:成分和类别节点,我们应该使用它来匹配必要的成分和类别,然后在开始时过滤食谱,以便我们只使用这些类别的食谱配料。这也可以让我们避免匹配和收集类别和成分,直到我们完成过滤。我已经更新了相应的查询。

+0

还在collect()中添加了成分的数量。 – InverseFalcon

+0

谢谢!我将需要研究这个查询来充分理解它。但是在运行时,我得到'Variable'c'not defined',尝试将其更改为'cat',但无论如何都得到相同的错误。 – Amygdaloideum

+0

发现错误,我没有更新我的匹配:类别。它应该现在运行。至于研究查询,通常有助于查看查询是如何逐个构建的。你可以在不同的地方用RETURN代替WITH(删除查询的其余部分)来看看我们如何建立结果。 – InverseFalcon

尝试收集的成分和分类收集,并进行对这些藏品的检查。 RETURN子句有点简化,但让我们先看看它是否起作用。

MATCH (recipe:Recipe) 
OPTIONAL MATCH (recipe)-[a:CONTAINS]->(i:Ingredient) 
OPTIONAL MATCH (recipe)-[:IS]->(c:Category) 
OPTIONAL MATCH (recipe)<-[:AUTHORED]-(u:User) 
OPTIONAL MATCH (recipe)<-[reaction:REACTS]-(beholder:User {cuid: 'some-id'}) 
WITH recipe, collect(i) AS ingredients, collect(c) AS categories, u, reaction, beholder 
WHERE ALL(
    ingredient IN ['tomato', 'banana'] 
    WHERE ingredient in ingredients 
) 
AND ALL(
    category IN ['smoothie'] 
    WHERE category in categories 
) 
RETURN DISTINCT recipe, 
    {username: u.username, cuid: u.cuid} AS author, 
    {love: reaction.love, favorite: reaction.favourite} AS interactions, 
    ingredients, 
    categories