具有不同匹配条件的Cypher语句返回相同的结果

时间:2020-02-05 13:19:21

标签: database neo4j cypher

我正在使用Neo4j作为数据库来存储与另一个数据库对象有关的投票信息。

我有一个Vote对象,其中包含以下字段:

  • type:String,其值为UPDOWN
  • argId:String是链接到唯一参数对象的字符串ID值

我正在尝试使用以下查询来查询分配给给定argId的投票数:

MATCH (v:Vote) WHERE v.argId = '214' AND v.type='DOWN'
RETURN {downvotes: COUNT(v)} AS votes
UNION
MATCH (v:Vote) WHERE v.argId = '214' AND v.type='UP'
RETURN {upvotes: COUNT(v)} AS votes

请注意,以上密码-可以正常工作并返回预期结果:

[
 {
   "downvotes": 1
 },
 {
   "upvotes": 10
 }
]

但是我觉得查询可能会更整洁,并且想要编写如下内容:

MATCH (v:Vote) WHERE v.argId = '214' AND v.type='UP'
MATCH (b:Vote) WHERE b.argId = '214' AND b.type='DOWN'
RETURN {upvotes: COUNT(v), downvotes: COUNT(b)}

只要通读一下,我认为这是有道理的,b和v被声明为单独的变量,所以一切都应该很好(所以我认为)。

但是运行它给了我这个:

{
  "upvotes": 10,
  "downvotes": 10
}

但这应该是我上面的内容。

这是为什么?

我是neo4j和cypher的新手,所以我可能还不了解cypher的工作原理。

任何人都可以发光吗?

谢谢!

p.s。我正在使用Neo4j 3.5.6,并通过桌面网络浏览器应用程序运行查询。

1 个答案:

答案 0 :(得分:0)

我认为,如果您运行此查询,则可以更清楚地了解正在发生的事情。您的查询产生upvotes(10)和downvotes(1)的笛卡尔积。该乘积是10行的结果集。随后计算它们时,每个都有十个。

MATCH (v:Vote) WHERE v.argId = '214' AND v.type='UP'
MATCH (b:Vote) WHERE b.argId = '214' AND b.type='DOWN'
RETURN v.type, b.type

要获得结果,您需要过滤值并分别进行计数。

有两个匹配语句,而不是两个match语句,它检索所有感兴趣的值,然后使用条件语句将它们过滤到upvotes和downbotes存储桶中。

类似的东西可能适合您。

MATCH (v:Vote {argId: '214'}) 
WHERE v.type IN ['UP', 'DOWN']
RETURN { 
          upvotes: count(CASE WHEN v.type = 'DOWN' THEN 1 END), 
          downvotes: count(CASE WHEN v.type = 'UP' THEN 1 END) 
       } AS vote_result

使用APOC,您可以执行类似的操作,即使用类型值本身来汇总计数,然后使用APOC将其转换为以类型为地图键的地图。

MATCH (v:Vote {argId: '214'}) 
WHERE v.type IN ['UP', 'DOWN']
WITH [v.type, count(*)] AS vote_pair
RETURN apoc.map.fromPairs(collect(vote_pair)) AS votes