Meu banco de dados Neo4j 3.2 possui nós (n)
que pode ter :OWNER
relações com outros nós. Eu quero encontrar todos os nós (n)
com :OWNER
relações especificamente com nós (a)
, (b)
e (c)
e especificamente não para outros nós.
Eu teria pensado que isso seria facilmente realizado com
MATCH (n), (o)
WHERE (
(n)-[:OWNER]->(o) AND o.uuid IN $owner_ids
AND NOT ((n)-[:OWNER]->(o) AND NOT o.uuid IN $owner_ids)
RETURN (n)
Mas isso não funciona. Essa consulta retorna nós incorretamente (n)
com :OWNER
relações com (a)
, (b)
, (c)
, e (d)
. Eu também tentei
MATCH (n), (o)
WHERE (n)-[:OWNER]->(o) AND o.uuid IN $owner_ids
WITH (n),(o)
WHERE NOT ((n)-[:OWNER]->(o) AND NOT o.uuid IN $owner_ids)
RETURN (n)
Assim como o que parece um milhão de outras permutações sem sucesso. Todas as sugestões são muito apreciadas!
ATUALIZAR
O cenário acima é um cenário simplificado. Conforme solicitado em um comentário, um exemplo mais próximo da realidade é:
MATCH (a)<-[:ANSWER]-(:Person {uuid: $person_id}), (o)
WHERE (exists((o)<-[:OWNER]-(:Owner)<-[:OWNER]-(:Form)-[:ANSWER]->(a)) AND o.uuid IN $owner_ids)
AND NOT (exists((o)<-[:OWNER]-(:Owner)<-[:OWNER]-(:Form)-[:ANSWER]->(a)) AND NOT o.uuid IN $owner_ids)
RETURN (a)
A resposta completa é
MATCH (o)<-[:OWNER]-(:Owner)<-[:OWNER]-(:Form)-[:ANSWER]->(a)<-[:ANSWER]-(:Person {uuid: $person_id})
WHERE o.uuid IN $owner_ids
WITH (a), count(o) as cnt
WHERE cnt = size(()<-[:OWNER]-(:Owner)<-[:OWNER]-(:Form)-[:ANSWER]->(a))
RETURN (a)
Respostas:
1 para resposta № 1Supondo que você adicione rótulos ao seu gráfico (vamos usar:Nó por enquanto, embora não esteja claro em sua descrição se todos os nós devem ser iguais ou se alguns devem usar rótulos diferentes), e se você tem uma restrição exclusiva em: Nó (uuid) para pesquisa rápida, isso deve funcionar:
MATCH (n:Node)-[:OWNER]->(o:Node)
WHERE o.uuid IN $owner_ids
WITH n, count(o) as cnt
WHERE cnt = size((n)-[:OWNER]->())
RETURN n
Sua consulta apresentou um produto cartesiano entre n
e o
(o produto cruzado de todos os nós de seu gráfico entre si), que não terá um bom desempenho. Você precisa especificar o relacionamento no MATCH, não no WHERE.
Quanto ao resto da consulta, estamos obtendo, para cada n
, a contagem de o
nós (aqueles com os ids em questão), e garantindo que o número de relacionamentos: OWNER para cada n
é igual a essa contagem. Se for maior, então existem: Relacionamentos OWNER com outros nós, portanto, eles são filtrados.
o size()
função que estamos usando, uma vez que não estamos especificando nada para o nó final, é eficiente em obter contagens de relacionamento.
0 para resposta № 2
Se o seu requisito era ter todos os três relacionamentos: OWNER presentes (não apenas qualquer subconjunto deles), então eu usaria esta consulta:
WITH ["a", "b", "c"] AS ids
MATCH (n:Node)-[:OWNER]->(o:Node)
WITH n,
COUNT(CASE WHEN o.uuid IN ids THEN 1 END) AS matches_found,
size(ids) AS matches_desired,
count(o) AS total_relationships
WHERE matches_found = matches_desired
AND matches_found = total_relationships
RETURN n
ORDER BY n.uuid