Neo4j Cypher Query multiple relationship from same node - neo4j

I Have a node called Member it has Relationships to Clubs and Shops I want to create a query so that I can return Member with Clubs and Shops
MATCH (m: Member { username: $memberUsername ,
password: $password})<- [r: MEMBER_BELONGS_TO_CLUBS] - (c: Club)
RETURN m, c, r
in the example I get Member and Clubs but I want to get member Clubs and member Shops

If your node M is connected like this S -> M <- C (M is Member, S is Shop, and C is Club), then you can use query similar like example in 4.2 Multiple Relationships in documentation:
MATCH (s: Shop) - [rs: MEMBER_BELONGS_TO_SHOPS] ->
(m: Member { username: $memberUsername ,
password: $password}) <- [r: MEMBER_BELONGS_TO_CLUBS] - (c: Club)
RETURN m, c, r, s, rs
Also you can use syntax like in this example with multiple MATCH:
MATCH (m: Member { username: $memberUsername ,
password: $password})
MATCH (s: Shop) - [rs: MEMBER_BELONGS_TO_SHOPS] -> (m)
MATCH (m) <- [r: MEMBER_BELONGS_TO_CLUBS] - (c: Club)
RETURN m, c, r, s, rs
And both queries returns something only if M is connected with both S and C. If you
don't want that restrictions you can use OPTIONAL MATCH documentation.

Related

How to limit the amount of certain node types in my path?

Say I have the following graph:
(:A) -> (:B {hasAttr: 'yes'}) -> (:C) -> (:B {hasAttr: 'yes'})
I want to find out the path between node type A and node type B. But I only need the path that contains one node type B. So the query return should be
(:A) -> (:B {hasAttr: 'yes'})
What is the right query?
You can use the SINGLE() predicate function (see https://neo4j.com/docs/cypher-manual/current/functions/predicate/#functions-single)
MATCH p = ...
WHERE SINGLE(node IN nodes(p) WHERE node:B)
Graphileon is correct. Use the function SINGLE() to return nodes with exactly one node that has a property.hasAttr = 'yes'. Below is a working query.
MATCH
p = (:A)-->(:B)
WHERE
single(var IN nodes(p) WHERE var.hasAttr = 'yes')
RETURN p
Sample graph found in https://neo4j.com/docs/cypher-manual/current/functions/predicate/#functions-single
MATCH p = (n)-->(b)
WHERE
n.name = 'Alice'
AND single(var IN nodes(p) WHERE var.eyes = 'blue')
RETURN p
Result:
╒══════════════════════════════════════════════════════════════════════╕
│"p" │
╞══════════════════════════════════════════════════════════════════════╡
│[{"name":"Alice","eyes":"brown","age":38},{},{"name":"Bob","eyes":"blu│
│e","age":25}] │
└──────────────────────────────────────────────────────────────────────┘

Neo4j - Is it possible to select a shortest path where nodes with a certain label have a particular value?

If I have two graphs
a:Test -> b:Foo({type = 'car'}) -> c:Test -> d:Foo({type = 'car'}) -> e:Test
a:Test -> b:Foo({type = 'car'}) -> c:Test -> d:Foo({type = 'bike'}) -> e:Test
I want to write a shortest path query that will match the first path predicated on intermediate nodes of type Foo with type = car, but then fails to find the second a path in the second graph.
MATCH (a:Test {id: '1'} ),
(e:Test {id: '5'}),
p = shortestPath((a)-[:REL*]-(e))
WHERE all(r IN nodes(p) WHERE r.type = 'car')
RETURN p
But this obviously doesn't work, maybe with a subquery?
Not sure how optimized this is, but it probably does the job. Basically we introduce a nested list comprehension syntax:
MATCH (a:Test {id: '1'} ),
(e:Test {id: '5'}),
p = shortestPath((a)-[:REL*]-(e))
WHERE all(r IN [x in nodes(p) where x:Foo] WHERE r.type = 'car')
RETURN p

How do you return created relationships using apoc.refactor.cloneNodes([nodes], true)?

The signature of apoc.refactor.cloneNodes() returns
"apoc.refactor.cloneNodes(nodes :: LIST? OF NODE?, withRelationships = false :: BOOLEAN?, skipProperties = [] :: LIST? OF STRING?) :: (input :: INTEGER?, output :: NODE?, error :: STRING?)"
The function only yields nodes for output. Is there a way to return relationships as well, or do you have to query these manually?
My current implementation looks like this, but I thought there might be a better way?
MATCH (n) WHERE n.id IN $ids
WITH collect(n) as nodes
CALL apoc.refactor.cloneNodes(nodes,true) yield output
MATCH (output)-[r]-()
SET output.id = apoc.create.uuid(), r.id = apoc.create.uuid()
WITH collect({source:startnode(r), edge:r, target:endnode(r) }) as edges, collect (distinct output) as nodes
RETURN *
search tag: apoc.refactor.cloneNodesWithRelationships (deprecated)
Updated to avoid cartesian products, and clarify nodesToClone and nodes:
MATCH (n) WHERE n.id in $ids
WITH collect(n) as nodesToClone
CALL apoc.refactor.cloneNodes(nodesToClone,true) yield output
SET output.id = apoc.create.uuid()
WITH output
MATCH (output)-[r]-()
SET r.id = apoc.create.uuid()
WITH collect({source:startnode(r), edge:r, target:endnode(r) }) as edges, collect (distinct output) as nodes
RETURN *
Your approach looks pretty reasonable.
However, (this is a minor side issue) the query would set the id of an output multiple times if it has multiple relationships. If you want to avoid the unnecessary overhead, you can replace this:
...
MATCH (output)-[r]-()
SET output.id = apoc.create.uuid(), r.id = apoc.create.uuid()
...
with this:
...
SET output.id = apoc.create.uuid()
WITH output
MATCH (output)-[r]-()
SET r.id = apoc.create.uuid()
...
[UPDATE]
In your updated query, you can avoid using the DISTINCT option in collect (distinct output) this way:
MATCH (n) WHERE n.id in $ids
WITH COLLECT(n) AS nodesToClone
CALL apoc.refactor.cloneNodes(nodesToClone,true) YIELD output
SET output.id = apoc.create.uuid()
WITH COLLECT(output) AS nodes
UNWIND nodes AS node
MATCH (node)-[r]-()
SET r.id = apoc.create.uuid()
WITH COLLECT({source:startnode(r), edge:r, target:endnode(r) }) AS edges, nodes
RETURN *

how to write a cypher statement to find out first match node i want

I have nodes like this:
(a {export:true})->(b {export:false})->(c {export:false})->
.....some other nodes with export field is false->
(d {export:true})->(e {export:true})
Now I only want to find out a and d, which have a relationship
(a {export:true})-->(b {expor:true})
I write some cypher statements, but can not work, they will return a->d and a->e. do somebody knows how to write a cypher statement that can work like I want?
thanks you
Answer A
The following query returns all connected export:true node pairs separated by 0 or more nodes that all contain export:false.
MATCH p=(a { export:true })-[*]->(b { export:true })
WHERE
LENGTH(p) = 1 OR
ALL (x IN NODES(p)[1..LENGTH(p)-1] WHERE NOT x.export)
RETURN a, b;
Note: LENGTH(p) returns the number of relationships in path p.
Answer B
Answer A can actually be simplified by removing the LENGTH(p) = 1 test:
MATCH p=(a { export:true })-[*]->(b { export:true })
WHERE ALL (x IN NODES(p)[1..LENGTH(p)-1] WHERE NOT x.export)
RETURN a, b;
But why this simplified query also works requires more of an explanation. If LENGTH(p) is 1, then:
NODES(p)[1..0] results in [], and
ALL(x IN [] WHERE ...) results in true (no matter what ... is).

Neo4j Finding path but without a certain node

I am not very familiar with Neo4j because I just used it for several days.
But now I want to find path between two nodes
like path : A & D
A -> B -> C -> D
A -> B -> E -> D
A -> C -> E -> D
and using "WHERE NOT" to eliminate Node B
so I will leave path A -> C -> E -> D
is there any way I can do this ?
Here is my Cypher:
MATCH (home { name:'Grove' }),(school { name:'Moulton' }),(Ann {name:'Ann'}),
p = ((home)-[*..4]->(school))
WHERE NOT ((home)-[]->(Ann))
RETURN p
It's not working for me
You can use the NONE predicate in the WHERE clause to filter out paths containing the B node. See http://console.neo4j.org/?id=hppthl for an example.
The cypher statement looks like this:
MATCH p=(:Person { name:'A' })-[:KNOWS*..4]->(:Person { name:'D' }),
(without:Person { name:'B' })
WHERE NONE (x IN nodes(p) WHERE x=without)
RETURN p

Resources