Let's say we have this cypher
match (n:Person{pid:322})-[k*1..2]->(s) return k
k would be a Collection of all relation originating from a specific node n in at most 2 hops.
How can I get all Node-Relation-Node where Relation is in k? It's something like match (a)-[b]->(c) foreach b in k return a,b,c but I know this query is invalid since foreach keyword in Neo4J can't be used in this case.
Edit:
I think I should add some illustration to make things clearer. Here I use an example from Neo4J documentation:
When I start from Charlie Sheen and using 1..2 range, the query must return (assuming the query ends with return a,b,c)
a | b | c
Charlie Sheen | ACTED_IN | Wall Street
Charlie Sheen | FATHER | Martin Sheen
Martin Sheen | ACTED_IN | The American President
Martin Sheen | ACTED_IN | Wall Street
This query should produce the a, b, and c values your edited question asks for (assuming you always want the name property values):
MATCH (n:Person{pid:322})-[k*1..2]->(s)
WITH LAST(k) AS lk
RETURN STARTNODE(lk).name AS a, TYPE(lk) AS b, ENDNODE(lk).name AS c;
I'm not sure why that wouldn't just be:
match (n:Person{pid:322})-[k*1..2]->(s) return n,k,s
Unless I'm misunderstanding your question.
A path will give you the sequence of nodes and relationsjips from n to s via k
MATCH p=(n:Person{pid:322})-[k*1..2]->(s) return p
You can also extract only the nodes and/or only the relationships from the path using nodes(p) or rels(p)
Related
In neo4j my database consists of chains of nodes. For each distinct stucture/layout (does graph theory has a better word?), I want to count the number of chains. For example, the database consists of 9 nodes and 5 relationships as this:
(:a)->(:b)
(:b)->(:a)
(:a)->(:b)
(:a)->(:b)->(:b)
where (:a) is a node with label a. Properties on nodes and relationships are irrelevant.
The result of the counting should be:
------------------------
| Structure | n |
------------------------
| (:a)->(:b) | 2 |
| (:b)->(:a) | 1 |
| (:a)->(:b)->(:b) | 1 |
------------------------
Is there a query that can achieve this?
Appendix
Query to create test data:
create (:a)-[:r]->(:b), (:b)-[:r]->(:a), (:a)-[:r]->(:b), (:a)-[:r]->(:b)-[:r]->(:b)
EDIT:
Thanks for the clarification.
We can get the equivalent of what you want, a capture of the path pattern using the labels present:
MATCH path = (start)-[*]->(end)
WHERE NOT ()-->(start) and NOT (end)-->()
RETURN [node in nodes(path) | labels(node)[0]] as structure, count(path) as n
This will give you a list of the labels of the nodes (the first label present for each...remember that nodes can be multi-labeled, which may throw off your results).
As for getting it into that exact format in your example, that's a different thing. We could do this with some text functions in APOC Procedures, specifically apoc.text.join().
We would need to first add formatting around the extraction of the first label to add the prefixed : as well as the parenthesis. Then we could use apoc.text.join() to get a string where the nodes are joined by your desired '->' symbol:
MATCH path = (start)-[*]->(end)
WHERE NOT ()-->(start) and NOT (end)-->()
WITH [node in nodes(path) | labels(node)[0]] as structure, count(path) as n
RETURN apoc.text.join([label in structure | '(:' + label + ')'], '->') as structure, n
with the bus Station problem, how can i did not pass same station with the Cypher eg not any Node? or the relationship
StationF--StationG
| |
StationA--StationB--StationC--StationD--StationE
| |
Station H
for example, I want not to pass the StationC-StationH And
StationH-StasionD
match(a:StationA)-[r:Road]-(z:StationE)
not any (node in nodes(p) | node.station) = StationH
If you are just trying to find the shortest path between a and z, you can use the shortestpath function.
For example:
MATCH (a:StationA), (z:StationE), p = shortestPath((a)-[:Road*]-(z))
RETURN p
Is it possible to return nodes which do not relate to a specific label at the end of the relationship links. E.g.
(EndTargetNode)<--MYREL---(SomeNode)<--MYREL---(SomeNode)<--MYREL---(SomeNode)
/ |
/ MYREL
(Node)<---SOME_REL---(SomeNode)<----MYREL---- |
v
(SomeNode)
|
MYREL
|
v
(SomeNode)
I'd like to match all SomeNodes which do not end with a MYREL relation to a Node with type EndTargetNode AND have at least 2 MYREL relationships. How would I go about this? Thanks
So far i've manage to just find nodes with the multiple MYREL relationships:
match (n)-[rel:MYREL]->(e)
with n, count(e) as rels
where rels > 1
return n;
This query will do it and reads just like your definition:
// I want all :SomeNode
MATCH (n:SomeNode)
// not related to an :EndTargetNode
WHERE NOT (n)-[:MYREL]->(:EndTargetNode)
// and with at least 2 MYREL relationships
AND size((n)-[:MYREL]->()) >= 2
RETURN n
I would like to query for various things and returned a combined set of relationships. In the example below, I want to return all people named Joe living on Main St. I want to return both the has_address and has_state relationships.
MATCH (p:Person),
(p)-[r:has_address]-(a:Address),
(a)-[r1:has_state]-(s:State)
WHERE p.name =~ ".*Joe.*" AND a.street = ".*Main St.*"
RETURN r, r1;
But when I run this query in the Neo4J browser and look under the "Text" view, it seems to put r and r1 as columns in a table (something like this):
│r │r1 │
╞═══╪═══|
│{} │{} │
rather than as desired with each relationship on a different row, like:
Joe Smith | has_address | 1 Main Street
1 Main Street | has_state | NY
Joe Richards | has_address | 22 Main Street
I want to download this as a CSV file for filtering elsewhere. How do I re-write the query in Neo4J to get the desired result?
You may want to look at the Cypher cheat sheet, specifically the Relationship Functions.
That said, you have variables on all the nodes you need. You can output all the data you need on each row.
MATCH (p:Person),
(p)-[r:has_address]-(a:Address),
(a)-[r1:has_state]-(s:State)
WHERE p.name =~ ".*Joe.*" AND a.street = ".*Main St.*"
RETURN p.name AS name, a.street AS address, s.name AS state
That should be enough.
What you seem to be asking for above is a way to union r and r1, but in such a way that they alternate in-order, one row being r and the next being its corresponding r1. This is a rather atypical kind of query, and as such there isn't a lot of support for easily making this kind of output.
If you don't mind rows being out of order, it's easy to do, but your start and end nodes for each relationship are no longer the same type of thing.
MATCH (p:Person),
(p)-[r:has_address]-(a:Address),
(a)-[r1:has_state]-(s:State)
WHERE p.name =~ ".*Joe.*" AND a.street = ".*Main St.*"
WITH COLLECT(r) + COLLECT(r1) as rels
UNWIND rels AS rel
RETURN startNode(rel) AS start, type(rel) AS type, endNode(rel) as end
I'm trying to do a count of nodes connected to node A, where node A is part of a Cypher query starting from node B, and I'm getting unexpected results. Here's an example setup. Pretend we're looking at books and owners, and books cite other books while owners of course own books:
Book B1
Book B2 CITES B1
Book B3 CITES B1
Book B4
Owner O1 OWNS B1
Owner O2 OWNS B2
Owner O3 OWNS B3 and B4
So let's say I'm looking at Book B1, and I want to find each book that cites it, then count the books owned by each person who owns the citing book. So if I start with B1, I should find owners O2 and O3, since each owns a book that cites B1. If I count the books they own, I should get 1 for O2, and 2 for O3.
So first, a query to just list the owners works fine:
start a=node(1) MATCH a<-[:CITES]-b<-[:OWNS]-c return c.name
That returns the names as expected. But then this query:
start a=node(1) MATCH a<-[:CITES]-b<-[:OWNS]-c-[:OWNS]->d return c.name, count(d)
It seems as though it should get to c, which is the list of owners, then go through the OWNS relationship to the owned books as d, and count them. But instead I get:
+--------------------+
| c.name | count(d) |
+--------------------+
| "O3" | 1 |
+--------------------+
It feels like it's leaving out the books/nodes that have already been found through the other OWNS link -- the ones represented by b. Is there any way to do this in a single query, or is it best to gather up the owners as c, then query again for each of them? It feels like this should be possible, but I haven't figured it out yet. Any ideas would be great -- thanks in advance.
You're right, once a node gets found, you can't find it again in the same match under a different named variable. You can break this up using a WITH, and then use d in the same way, and it will match all of them.
START a=node(14)
MATCH a<-[:CITES]-b<-[:OWNS]-c
WITH c MATCH c-[:OWNS]->d
RETURN c.name, count(d);
http://console.neo4j.org/?id=x1jst9