我有客户节点,第二个节点是地址
有客户LOCATED_IN地址
我想让所有位于同一城市的客户,返回城市,计数和客户名称按计数desc排序
MATCH (c:Customer)-[:LOCATED_IN]->(a:Address)
WITH a.city as city, count(*) as count
WHERE count > 1
RETURN city, count, collect(c.name)
ORDER BY count DESC;
c未定义(第4行,第29栏(偏移:120)) "返回城市,统计,收集(c.name)" ^ Neo.ClientError.Statement.InvalidSyntax
如果我删除" collect(c.name)"查询工作正常但是,那么我想念一些我想要的信息......
答案 0 :(得分:2)
正如TrueDub所说,您需要在WITH
子句中随身携带您想要返回的所有内容。
但是,您无法将a.city
,count(*)
和 c
并期望count(*)
成为城市中的客户数量。
原因是,为了计算每个城市的客户,您需要汇总客户。
但在这里,您将个人客户(c
)带到您身边,并使个人客户阻止客户聚合。
这就是你获得1
的原因,因为没有聚合的计数只意味着计算单个结果项。
您可以通过在WITH
子句中引入两件事来轻松解决此问题:地址/城市和客户集合。当您携带个人地址/城市并汇总客户时,您将获得每个城市的客户汇总。
WITH a.city, COLLECT(c) as customers
然后您可以过滤该集合的大小。
WHERE SIZE(customers) > 1
一个额外的和未经请求的注释:您的查询现在的工作方式,它在进行过滤之前读取属性。
这样做效率不高,因为它会读取可能会被丢弃的结果项的属性。
根据您的:Address
节点的外观 1 ,您可以在不触及任何属性的情况下进行收集和过滤。
这对性能来说是理想的。
请参阅Michael Hunger 5 Secrets to More Effective Neo4j 2.2. Query Tuning中的提示#4:推迟财产访问。
MATCH (customer:Customer)-[:LOCATED_IN]->(address:Address)
WITH address, COLLECT(customer) as customersAtAddress
WHERE SIZE(customersAtAddress) > 1
RETURN address.city as city,
SIZE(customersAtAddress) as customerCount,
EXTRACT(customer IN customersAtAddress | customer.name) as customerNames
现在,查询会在获取任何属性之前排除那些只有一个客户的地址,并且客户位于每个地址的集合中。由于客户在一个集合中,我们使用EXTRACT
来浏览集合并读取每个客户的名称。 EXTRACT
会返回一个新集合,因此您的结果将类似于。
city customerCount customerNames
-------------------------------------------------------------------------------
Säby 2 [Anders Järhed, Matilda Fridlund]
Frinnaryd 3 [Bo-Erik Jonsson, Annelie Sjöström, Ulf Eliasson]
1 我说“取决于你的
:Address
节点的样子,因为我不知道你是否有许多共享一个城市的地址节点。如果你这样做,那么您有一个不同的问题。我建议的查询(以及您自己的查询)将为您提供每个地址节点的客户集合。如果您有两个地址节点用于城市Säby
,那么您将获得两个结果Säby
的项目,有两个不同的客户集合。解决方案可能是稍微更改您的模型,并将城市移动到自己的节点,与“拥有”该城市的不同地址有关系。我知道如果是这种情况,也许我可以就此提出建议。
最后,上面的查询计算了两次集合的大小。这不是那么昂贵,而且值可能是由查询引擎缓存的。但是如果您想确定,可以添加另一个WITH
子句来计算一次值并将其绑定到标识符。然后查询出现为
MATCH (customer:Customer)-[:LOCATED_IN]->(address:Address)
WITH address, COLLECT(customer) as customersAtAddress
WITH address, customersAtAddress, COUNT(customersAtAddress) as customerCount
WHERE SIZE(customersAtAddress) > 1
RETURN address.city as city,
customerCount,
EXTRACT(customer IN customersAtAddress | customer.name) as customerNames
答案 1 :(得分:1)
我认为你需要将c带入WITH子句,如下所示:
MATCH (c:Customer)-[:LOCATED_IN]->(a:Address)
WITH a.city as city, count(*) as count, c
WHERE count > 1
RETURN city, count, collect(c.name)
ORDER BY count DESC;