Cypher - given relationship, get the nodes - neo4j

If I do the query
MATCH (:Label1 {prop1: "start node"}) -[relationships*1..10]-> ()
UNWIND relationships as relationship
RETURN DISTINCT relationship
How do I get nodes for each of acquired relationship to get result in format:
╒════════╤════════╤═══════╕
│"from" │"type" │"to" │
╞════════╪════════╪═══════╡
├────────┼────────┼───────┤
└────────┴────────┴───────┘
Is there a function such as type(r) but for getting nodes from relationship?

RomanMitasov and ray have working answers above.
I don't think they quite get at what you want to do though, because you're basically returning every relationship in the graph in a sort of inefficient way. I say that because without a start or end position, specifying a path length of 1-10 doesn't do anything.
For example:
CREATE (r1:Temp)-[:TEMP_REL]->(r2:Temp)-[:TEMP_REL]->(r3:Temp)
Now we have a graph with 3 Temp nodes with 2 relationships: from r1 to r2, from r2 to r3.
Run your query on these nodes:
MATCH (:Temp)-[rels*1..10]->(:Temp)
UNWIND rels as rel
RETURN startNode(rel), type(rel), endNode(rel)
And you'll see you get four rows. Which is not what you want because there are only two distinct relationships.
You could modify that to return only distinct values, but you're still over-searching the graph.
To get an idea of what relationships are in the graph and what they connect, I use a query like:
MMATCH (n)-[r]->(m)
RETURN labels(n), type(r), labels(m), count(r)
The downside of that, of course, is that it can take a while to run if you have a very large graph.
If you just want to see the structure of your graph:
CALL db.schema.visualization()
Best wishes and happy graphing! :)

Yes, such functions do exist!
startNode(r) to get the start node from relationship r
endNode(r) to get the end node
Here's the final query:
MATCH () -[relationships*1..10]-> ()
UNWIND relationships as r
RETURN startNode(r) as from, type(r) as type, endNode(r) as to

Related

To get nodes and relationships between two specified nodes for review

I have a database containing millions of nodes and edge data and I want to get all the nodes and relationships data between two specified nodes.
Below is the sample data for the graph which has 7 nodes and 7 relationships.
To traverse from 1st node to 7th node I can use the variable length relationship approach and can get the nodes and relationships in between the first and 7th nodes (but in this approach we need to know the number of relationships and nodes between 1st and 7th node).
For using variable length relationship approach we have to specify the number where we will get the end node and it traverses in one direction.
But in my case I know the start and end node and don't know how many relationships and nodes are in between them. Please suggest how I can write a Cypher query for this case.
I have used the APOC spanning tree procedure where it returns ‘path’ from the 1st and 7th element, but it does not return the nodes and relationships. Can I get nodes and relationships data in return using the spanning tree procedure and how?
Is there any other way to get all nodes and relations between two nodes without using the APOC procedure?
Here is query with apoc procedure:
MATCH (start:temp {Name:"Joel"}), (end:temp {Name:"Jack"}) CALL apoc.path.spanningTree(start,{terminatorNodes:[end]}) YIELD path return path
Note: In our graph database nodes can have multi direction relations.
[Sample nodes and relationships snapshot]
: https://i.stack.imgur.com/nN9hk.png
I assume you do not want to have duplicates in your result, so my approach would be this
MATCH (start:temp {Name:"Joel"}), (end:temp {Name:"Jack"})
MATCH p=shortestPath((start)-[*]->(end))
UNWIND nodes(p) AS node
UNWIND relationships(p) AS rel
RETURN COLLECT(DISTINCT node) as nodes, COLLECT(DISTINCT rel) as rels
Might be better to use shortestPath operator to find the shortest path between two nodes.
MATCH (start:temp {Name:"Joel"}), (end:temp {Name:"Jack"})
MATCH p=shortestPath((start)-[*]->(end))
RETURN nodes(p) as nodes, relationships(p) as rels

Retrieve relationships between child nodes using neo4j cypher

I have a following network result when I run this query in neo4j browser:
MATCH (n1:Item {name: 'A'})-[r]-(n2:Item) Return n1,r,n2
At the bottom of the graph, it says: Displaying 6 nodes, 7 relationships.
But when I look on the table in the neo4j browser, I only have 5 records
n1,r,n2
A,A->B,B
A,A->C,C
A,A->D,D
A,A->E,E
A,A->F,F
So in the java code, when I get the list of records using the code below:
List<Record> records = session.run(query).list();
I only get 5 records, so I only get the 5 relationships.
But I want to get all 7 relationships including the 2 below:
B->C
C->F
How can i achieve that using the cypher query?
This should work:
MATCH (n:Item {name: 'A'})-[r1]-(n2:Item)
WITH n, COLLECT(r1) AS rs, COLLECT(n2) as others
UNWIND others AS n2
OPTIONAL MATCH (n2)-[r2]-(x)
WHERE x IN others
RETURN n, others, rs + COLLECT(r2) AS rs
Unlike #FrantišekHartman's first approach, this query uses UNWIND to bind n2 (which is not specified in the WITH clause and therefore becomes unbound) to the same n2 nodes found in the MATCH clause. This query also combines all the relationships into a single rs list.
There are many ways to achieve this. One ways is to travers to 2nd level and check that the 2nd level node is in the first level as well
MATCH (n1:Item {name: 'A'})-[r]-(n2:Item)
WITH n1,collect(r) AS firstRels,collect(n2) AS firstNodes
OPTIONAL MATCH (n2)-[r2]-(n3:Item)
WHERE n3 IN firstNodes
RETURN n1,firstRels,firstNodes,collect(r2) as secondRels
Or you could do a Cartesian product between the first level nodes and match:
MATCH (n1:Item {name: 'A'})-[r]-(n2:Item)
WITH n1,collect(r) AS firstRels,collect(n2) as firstNodes
UNWIND firstNodes AS x
UNWIND firstNodes AS y
OPTIONAL MATCH (x)-[r2]-(y)
RETURN n1,firstRels,firstNodes,collect(r2) as secondRels
Depending on on cardinality of firstNodes and secondRels and other existing relationships one might be faster than the other.

Duplicate object in a list when I try to map all related entities

According to this post I tried to map all related entities in a list.
I used the same query into the post with a condition to return a list of User but it returns duplicate object
MATCH (user:User) WHERE <complex conditions>
WITH user, calculatedValue
MATCH p=(user)-[r*0..1]-() RETURN user, calculatedValue, nodes(p), rels(p)
Is it a bug? I'm using SDN 4.2.4.RELEASE with neo4j 3.2.1
Not a bug.
Keep in mind a MATCH in Neo4j will find all occurrences of a given pattern. Let's look at your last MATCH:
MATCH p=(user)-[r*0..1]-()
Because you have a variable match of *0..1, this will always return at least one row with just the user itself (with rels(p) empty and nodes(p) containing only the user), and then you'll get a row for every connected node (user will always be present on that row, and in the nodes(p) collection, along with the other connected node).
In the end, when you have a single user node and n directly connected nodes, you will get n + 1 rows. You can run the query in the Neo4j browser, looking at the table results, to confirm.
A better match might be something like:
...
OPTIONAL MATCH (user)-[r]-(b)
RETURN user, calculatedValue, collect(r) as rels, collect(b) as connectedNodes
Because we aggregate on all relationships and connected nodes (rather than just the relationships and nodes for each path), you'll get a single row result per user node.

Neo4j cypher - Counting immediate children of root nodes

I'm struggling with a problem despite having read a lot of documentation... I'm trying to find my graph root node (or nodes, they may be several top nodes) and counting their immediate children (all relations are typed :BELONGS_TO)
My graph looks like this (cf. attached screenshot). I have been trying the following query which works as long as the root node only has ONE incomming relationship, and it doesn not when it has more than one. (i'm not realy familiar with the cyhper language yet).
MATCH (n:Somelabel) WHERE NOT (()-[:BELONGS_TO]->(n:Somelabel)) RETURN n
Any help would be much appreciated ! (i haven't even tried to count the root nodes immediate children yet...which would be "2" according to my graph)
Correct query was given by cybersam
MATCH (n:Somelabel) WHERE NOT (n)-[:BELONGS_TO]->() RETURN n;
MATCH (n:Somelabel)<-[:BELONGS_TO]-(c:Somelabel)
WHERE NOT (n)-[:BELONGS_TO]->() RETURN n, count(c);
Based on your diagram, it looks like you are actually looking for "leaf" nodes. This query will search for all Somelabel nodes that have no outgoing relationships, and return each such node along with a count of the number of distinct nodes that have a relationship pointing to that node.
MATCH (n:Somelabel)
WHERE NOT (n)-[:BELONGS_TO]->()
OPTIONAL MATCH (m)-[:BELONGS_TO]->(n)
RETURN n, COUNT(DISTINCT m);
If you are actually looking for all "root" nodes, your original query would have worked.
As a sanity check, if you have a specific node that you believe is a "leaf" node (let's say it has an id value of 123), this query should return a single row with null values for r and m. If you get non-null results, then you actually have outgoing relationships.
MATCH (n {id:123})
OPTIONAL MATCH (n)-[r]->(m)
RETURN r, m

Neo4j cypher query with variable relationship path length

I'm moving my complex user database where users can be on one of many teams, be friends with each other and more to Neo4j. Doing this in a RDBMS was painful and slow, but is simple and blazing with Neo4j. :)
I was hoping there is a way to query for
a relationship that is 1 hop away and
another relationship that is 2 hops away
from the same query.
START n=node:myIndex(user='345')
MATCH n-[:IS_FRIEND|ON_TEAM*2]-m
RETURN DISTINCT m;
The reason is that users that are friends are one edge from each other, but users linked by teams are linked through that team node, so they are two edges away. This query does IS_FRIEND*2 and ON_TEAM*2, which gets teammates (yeah) and friends of friends (boo).
Is there a succinct way in Cypher to get both differing length relations in a single query?
I rewrote it to return a collection:
start person=node(1)
match person-[:IS_FRIEND]-friend
with person, collect(distinct friend) as friends
match person-[:ON_TEAM*2]-teammate
with person, friends, collect(distinct teammate) as teammates
return person, friends + filter(dupcheck in teammates: not(dupcheck in friends)) as teammates_and_friends
http://console.neo4j.org/r/oo4dvx
thanks for putting together the sample db, Werner.
I have created a small test database at http://console.neo4j.org/?id=sqyz7i
I have also created a query which will work as you described:
START n=node(1)
MATCH n-[:IS_FRIEND]-m
WITH collect(distinct id(m)) as a, n
MATCH n-[:ON_TEAM*2]-m
WITH collect(distinct id(m)) as b, a
START n=node(*)
WHERE id(n) in a + b
RETURN n

Resources