How to get Neo4j nodes linked through another node? - neo4j

I have node A and an associated node B.
Node C and node D are tied to node B too.
It is necessary to get all nodes A and associated with them C and D
MATCH (a:A) -- (:B) -- (c:C)
RETURN a, c
Received A and bound to it (via B) C.
Is it possible get node A, C and D in the same request?

You can write your query in two ways like below:
Option #1:
MATCH (a:A) -- (b:B) -- (c:C), (b) -- (d:D)
RETURN a, c, d
Option #2:
MATCH (a:A) -- (b:B) -- (c:C)
MATCH (b) -- (d:D)
RETURN a, c, d
which is basically the same thing with the first query.

Related

Get end nodes when using *

Lets say I have points a, b, c, d and a->b->c->d is related with next. Below is merge command for it.
merge (a:point{id:'a'})-[:next]-(b:point{id:'b'})-[:next]-(c:point{id:'c'})-[:next]-(d:point{id:'d'}) return a, b, c, d
Neo4j image of the merge
What I am looking for is a way to get all the points between a and d. Using below query I get the relationships, but how can I get list that contains b, c?
match p=(start:point)-[:next*]-(end:point)
with *, relationships(p) as r
where start.id ='a' and end.id = 'd'
return start, r, end
You can do
RETURN nodes(p)[1..-1]
to get the nodes except the first and last one.

Query to write hops and return all the properties from the middle nodes or a better way to do it and skip hops?

Node A is connected to Node E through different nodes B (B can be repeating), C and D etc as given below.
(A)--(C)--(D)--(E)
(A)--(B)--(C)--(D)--(E)
(A)--(B)--(B)--(C)--(D)--(E)
(A)--(B)--(B)--(B)--(C)--(D)--(E)
There could be up to 7 B nodes between A and C or no B node at all (like the first case above).
Question: How to get all the E1, E2, E3, E4 connected to A1 with a single query and return properties from all A, B, C, D and E nodes? I could not return the properties using the hops.
MATCH (A {Id:30})-[*1..6]-(E) RETURN DISTINCT A.Name, E.Name;
But we want to return B.Name (If there are multiple B nodes in the middle their names too), C.Name and D.Name too. Happy to skip hopping completely if required. Help please? Thanks in advance.
Try this
// in case there is always A,C and E, you can look for
// paths with length 3 to 6
MATCH path=(A)-[*3..6]-(E)
// return the name of each node in the same order
RETURN [n IN nodes(path) | n.name] AS nodeNames
Assuming A through E are node labels, this query should get all paths that match your pattern (with 0 to 7 B nodes between the A and C nodes), and return distinct lists of node Name values:
MATCH p=(:A)-[*..8]-(:C)--(:D)--(:E)
WHERE ALL(n IN NODES(p)[1..-3] WHERE 'B' IN LABELS(n))
RETURN DISTINCT [m IN NODES(p) | m.Name] AS names
In general, the query would be more efficient if you could also specify the relationship types and their directionality.

Cypher WHERE NOT EXISTS with named variable

In a Neo4J database, I need to find a (complex) pattern with 3 named node (let's say a, b, c) and some other non-named nodes, but only if there is no node (say "x") that connects to a, b, and c.
I'd like to write something like :
MATCH (a:A)-<something>-(b:B)-<something>-(c:C)
WHERE NOT EXISTS ((a)--(x:X)--(b), (x)--(c) )
RETURN a, b, c
But I get "Variable x not defined". It would be easy if x was only forbidden if connected to (a) and (b). And NOT EXISTS (a)--(:X)--(b) AND NOT EXISTS (a)--(:X)--(c) is too strong.
Any ideas?
You should try MATCHing x:X and using it the WHERE:
MATCH (x:X), (a:A)-<something>-(b:B)-<something>-(c:C)
WHERE NOT EXISTS ((a)--(x)--(b), (x)--(c) )
RETURN a, b, c

Getting nodes from paths

I have a path that returns a number of, well, paths. nodes(path) looks like:
[a, b, c, d],
[a, b, e],
[a, f]
What I want is to get all the nodes. So converting that path to
a
b
c
d
e
f
would be great. I would like to continue using the nodes in further cypher statements so leaving them in a collection doesn't work for me.
Any ideas?
EDIT 1
MATCH(t:THING1 {id:"t1"})-[:AFFECTS]->(x:SOME_NODE), (t)-[:CHANGES]->(SOME_NODE)
MATCH p=shortestpath((s)-[MY_RELATION*0..4]->(x))
WITH collect(nodes(p)) as nodes
WITH REDUCE(output = [], r IN nodes | output + r) AS flat
This produces a collection of nodes. Now to convert it into rows and dedup it...
You could just unwind the collections of nodes from the paths and then return the distinct ones.
MATCH(t:THING1 {id:"t1"})-[:AFFECTS]->(x:SOME_NODE), (t)-[:CHANGES]->(SOME_NODE)
MATCH p=shortestpath((s)-[MY_RELATION*0..4]->(x))
UNWIND nodes(p) as n
RETURN DISTINCT n

cypher query to return or keep only the final sequence when variable length relationship identifiers are used

Is there a way to keep or return only the final full sequences of nodes instead of all subpaths when variable length identifiers are used in order to do further operations on each of the final full sequence path.
MATCH path = (S:Person)-[rels:NEXT*]->(E:Person)................
eg: find all sequences of nodes with their names in the given list , say ['graph','server','db'] with same 'seqid' property exists in the relationship in between.
i.e.
(graph)->(server)-(db) with same seqid :1
(graph)->(db)->(server) with same seqid :1 //there can be another matching
sequence with same seqid
(graph)->(db)->(server) with same seqid :2
Is there a way to keep only the final sequence of nodes say ' (graph)->(server)->(db)' for each sequences instead of each of the subpath of a large sequence like (graph)->(server) or (server)->(db)
pls help me to solve this.........
(I am using neo4j 2.3.6 community edition via java api in embedded mode..)
What we could really use here is a longestSequences() function that would do exactly what you want it to do, expand the pattern such that a and b would always be matched to start and end points in the sequence such that the pattern is not a subset of any other matched pattern.
I created a feature request on neo4j for exactly this: https://github.com/neo4j/neo4j/issues/7760
And until that gets implemented, we'll have to make do with some alternate approach. I think what we'll have to do is add additional matching to restrict a and b to start and end nodes of full sequences.
Here's my proposed query:
WITH ['graph', 'server' ,'db'] as names
MATCH p=(a)-[rels:NEXT*]->(b)
WHERE ALL(n in nodes(p) WHERE n.name in names)
AND ALL( r in rels WHERE rels[0]['seqid'] = r.seqid )
WITH names, p, a, rels, b
// check if b is a subsequence node instead of an end node
OPTIONAL MATCH (b)-[rel:NEXT]->(c)
WHERE c.name in names
AND rel.seqid = rels[0]['seqid']
// remove any existing matches where b is a subsequence node
WITH names, p, a, rels, b, c
WHERE c IS NULL
WITH names, p, a, rels, b
// check if a is a subsequence node instead of a start node
OPTIONAL MATCH (d)-[rel:NEXT]->(a)
WHERE d.name in names
AND rel.seqid = rels[0]['seqid']
// remove any existing matches where a is a subsequence node
WITH p, a, b, d
WHERE d IS NULL
RETURN p, a as startNode, b as endNode
MATCH (S:Person)-[r:NEXT]->(:Person)
// Possible starting node
WHERE NOT ( (:Person)-[:NEXT {seqid: r.seqid}]->(S) )
WITH S,
// Collect all possible values of `seqid`
collect (distinct r.seqid) as seqids
UNWIND seqids as seqid
// Possible terminal node
MATCH (:Person)-[r:NEXT {seqid: seqid}]->(E:Person)
WHERE NOT ( (E)-[:NEXT {seqid: seqid}]->(:Person) )
WITH S,
seqid,
collect(distinct E) as ES
UNWIND ES as E
MATCH path = (S)-[rels:NEXT* {seqid: seqid}]->(E)
RETURN S,
seqid,
path
[EDITED]
This query might do what you want:
MATCH (p1:Person)-[rel:NEXT]->(:Person)
WHERE NOT (:Person)-[:NEXT {seqid: rel.seqid}]->(p1)
WITH DISTINCT p1, rel.seqid AS seqid
MATCH path = (p1)-[:NEXT* {seqid: seqid}]->(p2:Person)
WHERE NOT (p2)-[:NEXT {seqid: seqid}]->(:Person)
RETURN path;
It first identifies all Person nodes (p1) with at least one outgoing NEXT relationship that have no incoming NEXT relationships (with the same seqid), and their distinct outgoing seqid values. Then it finds all "complete" paths (i.e., paths whose start and end nodes have no incoming or outgoing NEXT relationships with the desired seqid, respectively) starting at each p1 node and having relationships all sharing the same seqid. Finally, it returns each complete path.
If you just want to get the name property of all the Person nodes in each path, try this query (with a different RETURN clause):
MATCH (p1:Person)-[rel:NEXT]->(:Person)
WHERE NOT (:Person)-[:NEXT {seqid: rel.seqid}]->(p1)
WITH DISTINCT p1, rel.seqid AS seqid
MATCH path = (p1)-[:NEXT* {seqid: seqid}]->(p2:Person)
WHERE NOT (p2)-[:NEXT {seqid: seqid}]->(:Person)
RETURN EXTRACT(n IN NODES(path) | n.name);

Resources