Get relationships and nodes between two nodes - graph

Given the following data set in Neo4j:
(A)-flows->(B)-flows->(C)-flows->(D)-flows->(Z)
(A)-flows->(E)-flows->(F)-flows->(Z)
(A)-flows->(G)-flows->(Z)
How can I return the subgraph (nodes B, C, D, E, F, G their relationships between each other and the relationships to A and Z) with a Cypher query when only A and Z is known.
Pseudo code:
Match(a)-[rels*](nodes*)-(z)
where a.Id = '123' and z.Id = '456'
return a,rels,nodes,z

Save the (A)->...->(Z) subgraph to a named path then use the nodes and relationships functions to extract a list of nodes and relationships:
MATCH p=(a {Id: '123'})-[:flows*]->(z {Id: '456'})
RETURN a, nodes(p), relationships(p), z
As pointed out in the comments, nodes(p) also returns a and z. If you do not want those nodes to be returned, omit the first and last elements of the list. Thanks to Bruno Peres and cybersam for their inputs.
MATCH p=(a {Id: '123'})-[:flows*]->(z {Id: '456'})
RETURN a, nodes(p)[1..-1], relationships(p), z
Remark #1. It is also possible to UNWIND these lists to their content process one-by-one.
Remark #2. Depending on the driver your using, you can simply return p and process it in the client's code. For example, the Java driver allows use to return a Path object that has nodes() and relationships() methods returning Iterables.

Related

How to traverse a graph and pattern-match a subgraph in Gremlin

I have a graph which is made of many instances of the same pattern (or subgraph).
The subgraph of interest is pictured below.
The relationship cardinality between the nodes are:
s -> c (one-many)
c -> p (many-many)
p -> aid (one-many)
p -> rA (one-one)
p -> rB (one-one)
p -> o (many-one)
The goal is to return a list of all instances of this subgraph or pattern as shown below
[
{
s-1,
c-1,
p-1,
aid-1,
o-1,
rA-1,
rB-1
},
{
s-2,
c-2,
p-2,
aid-2,
o-2,
rA-2,
rB-2
},
{
... so on and so forth
}
]
How do I query my graph to return this response?
I have tried using a combination of and() and or() as shown below, but that did not capture the entire subpattern as desired.
g.V().hasLabel('severity').as('s').out('severity').as('c').out('affecting').as('p')
.and(
out('ownedBy').as('o'),
out('rA').as('rA'),
out('rB').as('rB'),
out('package_to_aid').as('aid')
)
.project('p', 'c', 's', 'o', 'rA', 'r', 'aid').
by(valueMap()).
by(__.in('affecting').values('cve_id')).
by(__.in('affecting').in('severity').values('severity')).
by(out('ownedBy').values('name')).
by(out('rA').valueMap()).
by(out('rB').valueMap()).
by(out('package_to_aid').values('aid')).
I know I can use a series of out() and in() steps to traverse a non-branching path (for example the nodes: s->c->p), however I am struggling with capturing/traversing paths that branch out (for example, the node p and its 3 children nodes: rA, rB, and o)
I looked at Union() but I am unable to make it work either.
I am unable to find examples of similar queries online. Does Gremlin allow this sort of traversal, or do I have to remodel my graph as a Linked-list for this to work?
ps. I am doing this on Cosmos where Match() step is not supported

Match nodes where all relations satisfy constraints

I'm looking to find nodes that have relations where all relations satisfy that constraint. the exact example is do you have a relation in a list.
the graph is bascially cocktails, with the relations being ingredients. given a list of ingredients i want to know what I can make.
with ['Sweet Vermouth', 'Gin', 'Campari', 'Bourbon'] as list
...
should return Negroni, Boulevardier, ...
I've been finding this tricky because we want to make sure that all relations of a node satisfy the constraint, but the number of nodes could very easily be a subset of the list and not an exact match to the ingredient list.
this is the best I've done so far, and it only works if you have all the ingredients, but nothing extra.
with ['Sweet Vermouth', 'Gin', 'Campari', 'Bourbon'] as list
MATCH (n:Cocktail)-[h:HAS]-(x)
WITH list, count(list) AS lth, n, COLLECT(DISTINCT x.name) AS cx, collect(DISTINCT h) as hh
WHERE ALL (i IN list WHERE i IN cx)
RETURN n
I'ved looked at stackoverflow.com/a/62053139/974731. I don't think it solves my problem
as you can see the addition of Bourbon removes the Negroni, which shouldn't happen since all we've done is add an ingredient to our bar.
This should return all cocktails whose needed ingredients are in the have list.
WITH ['Sweet Vermouth', 'Gin', 'Campari', 'Bourbon'] as have
MATCH (c:Cocktail)-[:HAS]->(x)
WITH have, c, COLLECT(x.name) AS needed
WHERE ALL(n IN needed WHERE n IN have)
RETURN c
Or, if you pass have as a parameter:
MATCH (c:Cocktail)-[:HAS]->(x)
WITH c, COLLECT(x.name) AS needed
WHERE ALL(n IN needed WHERE n IN $have)
RETURN c
It's terribly hacky, but this is where I got
with ['Sweet Vermouth', 'Gin', 'Campari', 'Bourbon'] as list
call {
match (ali:Cocktail)--(ii:Ingredient) //pull all nodes
return ali, count(ii) as needed // get count for needed ingredients
}
MATCH (ali)--(i:Ingredient)
WHERE i.name in list // get ingredients that are in the list
WITH distinct ali.name as name, count(ali.name) as available, needed
WHERE available = needed
RETURN name;

Neo4J - Choose MATCH statement based on node property value

I'm attempting to MATCH on a specific path depending on the property of an initial node.
E.g. I have a node, n, that has a property called nodeType. If node type is A then use the first MATCH, if node type is B then use the second MATCH.
I've attempted this using FOREACH. So when the case that nodeType is A, then return the node and it's relationships to other nodes. If the return type is B, then return its relationship to other nodes. In this case, it can only be one or the other, so only one will return a result. However, and this may be syntactic errors on my part, but where I'm asking it to execute a MATCH query, I cannot define the variables within the FOREACH.
Any help would be great.
MATCH (n: testNode)
WITH n
FOREACH(_ IN CASE WHEN n.nodeType == "A" THEN [MATCH (n)-[r]-(n2: testNode)] ELSE [] END | WITH n, r, n2)
FOREACH(_ IN CASE WHEN n.nodeType == "B" THEN [MATCH (n)--(n0)-[r]-(n2: testNode)] ELSE [] END | WITH n, r, n2)
WITH n, r, n2
RETURN n, COLLECT(r), COLLECT(n2)
Note: This is not the actual semantics of my MATCH queries. I have made them different just to show that they will do different things, but return the same types of nodes and relationships.
Does something like this fit your needs?
BTW... in your example with n.nodeType == "B" you are returning r but you are not matching it in your query. I used different relationship types in the example below instead.
MATCH (n:testNode)
RETURN
CASE
WHEN n.nodeType = "A" THEN [(n)-[r:REL1]-(n2:testNode)| {n:n, r: type(r), n2: n2}]
WHEN n.nodeType = "B" THEN [(n)-[r:REL2]-(n2:testNode)| {n:n, r: type(r), n2: n2}]
END AS nodes

How to retrieve a node based on its top-most parent node in Neo4j

I have a hierarchy of node relationships like:
Organisation -> Department -> System -> Function -> Port - > Request -> Response -> Parameter
The query -
MATCH q=(p)-[*]->(b:checkoutby) WHERE p.name ="william" RETURN q
gives the entire network belonging to the Parent node -> william up-till the last node mentioned -> checkoutby.
However, I want only the two related nodes to appear.
I tried the query -
MATCH (n:william) WHERE n is null RETURN n UNION MATCH n=(p)-
[:Parameter]->(b) WHERE
b.name ="checkoutBy" RETURN n
But here the effect of "william" node i.e. the first parent node is nullified and we get the output irrespective of the parent node.
For which, I even tried this query -
MATCH (n) WHERE none(node in nodes(n) WHERE node:william) RETURN n
UNION MATCH n=(p)--()-[:Parameter]->(b) WHERE b.name ="cabinet"
RETURN n
but I get error -
Neo.ClientError.Statement.SyntaxError: Type mismatch: expected Path but was Node (line 1, column 36 (offset: 35))
"MATCH (n) WHERE none(node in nodes(n) WHERE node: william ) RETURN n UNION MATCH n=(p)--()-[:Parameter]->(b) WHERE b.name ="cabinet" RETURN n"
I even tried the intersection query but to no avail .
MATCH (n1:william), (n2),(q:cabinet)
WHERE (n1)<-[:Department]-() AND (n2)<-[:Parameter]-(q)
RETURN count(q), collect(q.name)
Warning Error-
This query builds a Cartesian product between disconnected patterns.
If a part of a query contains multiple disconnected patterns, this will build a Cartesian product between all those parts. This may produce a large amount of data and slow down query processing. While occasionally intended, it may often be possible to reformulate the query that avoids the use of this cross product, perhaps by adding a relationship between the different parts or by using OPTIONAL MATCH (identifier is: (n2))
EXPLAIN MATCH (n1:william), (n2),(ego:cabinet)
^
Even this query doesn't work -
MATCH (n:william) RETURN n UNION MATCH n=(p)-[:Parameter]->(b)
WHERE b.name ="checkoutBy"
call apoc.path.expandConfig(n, {labelFilter:'-william'}) yield path
return path
I want to retrieve the checkoutby / cabinet node only if it is from the topmost parent node (william).
I don't have reputations to comment so asking here:
It's not clear from your question if William is a Name property or a Label?
You used it as a name in the first query and as a Label in all other queries.
I am assuming it is a Label, It looks like it is a label from the screenshot you shared.
If you want to check if the checkoutby/cabinet node is related to William node and return only if it's related you can use the following query:
MATCH (w:william)-[*]-(c:checkoutby) return w,c
Please note: These type of queries consumes too much Memory.
If I've understood your problem the (b:checkoutby) node does not have any incoming relationships so you could write :
MATCH (p)-[*]->(b:checkoutby) WHERE p.name ="william" AND NOT EXISTS ( (b)-[]->()) RETURN p, b

Using Parameters in Neo4j Relationship Queries

I'm struggling to work around a small limitation of Neo4j in that I am unable to use a parameter in the Relationship section of a Cypher query.
Christophe Willemsen has already graciously assisted me in working my query to the following:
MATCH (n1:Point { name: {n1name} }),
(n2:Point { name: {n2name} }),
p = shortestPath((n1)-[r]->(n2))
WHERE type(r) = {relType}
RETURN p
Unfortunately as r is a Collection of relationships and not a single relationship, this fails with an error:
scala.collection.immutable.Stream$Cons cannot be cast to org.neo4j.graphdb.Relationship
Removing the use of shortestPath() allows the query to run successfully but returns no results.
Essentially my graph is a massive collection of "paths" that link "points" together. It is currently structured as such:
http://console.neo4j.org/r/rholp
I need to be able to provide a starting point (n1Name), an ending point (n2Name), and a single path to travel along (relType). I need a list of nodes to come out of the query (all the ones along the path).
Have I structured my graph incorrectly / not optimally? I am open to advice on whether the overall structure is not optimal as well as advice on how best to structure the query!
EDIT
Regarding your edit, the nodes() function returns you the nodes along the path :
MATCH p=allShortestPaths((n:Point { name:"Point5" })-[*]->(n2:Point { name:"Point8" }))
WHERE ALL (r IN rels(p) WHERE type(r)={relType})
RETURN nodes(p)
In the console link, it is returning nodes Points 5,6,7,8
I guess in your case that using a common relationship type name for connecting your Point nodes would be more efficient.
If having a Path1, Path2, .. is for knowing the distance between two points, you can easily know the distance by asking for the length of the path, like this query related to your console link :
MATCH (n:Point { name:"Point1" })
WITH n
MATCH (n2:Point { name:"Point4" })
WITH n, n2
MATCH p=shortestPath((n)-[]->(n2))
RETURN length(p)
If you need to return only paths having a defined relationship length, you can use it without the shortestPath by specifying a strict depth :
MATCH (n:Point { name:"Point1" })
WITH n
MATCH (n2:Point { name:"Point4" })
WITH n, n2
MATCH p=(n)-[*3..3]->(n2)
RETURN length(p)
LIMIT1
As you can see here, the need to specify the relationship is not mandatory, you can just omit it or add the :NEXT type if you have other relationship types in your graph
If you need to match on the type, for e.g. the path from point 5 to point 8 in your console link, and the path can only have a PATH_TWO relationship, then you can do this :
MATCH (n:Point { name:"Point5" })
WITH n
MATCH (n2:Point { name:"Point8" })
WITH n, n2
MATCH p=(n)-[r*]->(n2)
WHERE type(r[0])= 'PATH_TWO'
WITH p, length(p) AS l
ORDER BY l
RETURN p, l
LIMIT 1
If you really NEED to have the Path1, Path2 style, maybe a short explanation on the need could help us find the more appropriate query
MATCH p=shortestpath((n1:Point{name:{n1name}})-[:relType *]->(n2:Point {name:{n2name}}))
RETURN p

Resources