/ / Encontre nós (n) com: relações PROPRIETÁRIO para nós (a), (b) e (c) e nenhum outro nó - neo4j, cypher

Encontre nós (n) com: relações OWNER para nós (a), (b) e (c) e nenhum outro nó - neo4j, cypher

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 № 1

Supondo 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