In the latest version of Cypher, I can use this query to get all nodes with relationships:
MATCH (n)-[r]-(m) RETURN n,r,m
However, I'm missing nodes without any relationships.
In trying to query the missing nodes, this attempt gives me the error: Variable 'r' not defined
MATCH (n) WHERE NOT (n)-[r]->() RETURN n
And, this attempt shows zero results:
MATCH (n)-[r]->() WHERE r is null RETURN n
I can see the stragglers with:
MATCH (n) RETURN n
But, then I'm missing the relationships.
How do I phrase my query to find all nodes and all relationships without duplicates?
You can try the OPTIONAL MATCH:
MATCH (n)
OPTIONAL MATCH (n)-[r]-(m)
RETURN n, r, m
Related
How can I know how many nodes and edges are involved in a MATCH? Is there another way besides Explain / Profile Match?
If you mean how many nodes are matched in a path, such as a variable-length path, then you can assign a path variable for this:
MATCH p = (k:Person {name:'Keanu Reeves'})-[*..8]-(t:Person {name:'Tom Hanks'})
WITH p LIMIT 1
RETURN p, length(p) as pathLength, length(p) + 1 as numberOfNodesInPath
You can also use nodes(p) and relationships(p) to get the collection of nodes and relationships that make up the path, and you can use size() on those collections to get their size.
There exists the COUNT() function of Cypher that allows you to count the number of elements. As for example in this query:
MATCH (n)
RETURN COUNT(n);
This query will count all nodes in your database.
You can find more information in the cypher manual, under the aggregating functions. Check it out.
The following Cypher snippet should return the number of distinct nodes and relationships found by any given MATCH clause. Just replace <your code here> with your MATCH pattern.
MATCH <your code here>
WITH COLLECT(NODES(p)) AS ns, SUM(SIZE(RELATIONSHIPS(p))) AS relCount
UNWIND ns AS nodeList
UNWIND nodeList AS node
RETURN COUNT(DISTINCT node) AS nodeCount, relCount;
So as a complication to this question, I basically want to do
MATCH (n:TEST) OPTIONAL MATCH (n)-[r]->() RETURN DISTINCT n, r
And I want to return n and r as one column with no repeat values. However, running
MATCH (n:TEST) OPTIONAL MATCH (n)-[r]->() UNWIND n+r AS x RETURN DISTINCT x
gives a "Type mismatch: expected List but was Relationship (line 1, column 47)" error. And this query
MATCH (n:TEST) RETURN DISTINCT n UNION MATCH ()-[n]->() RETURN DISTINCT n
Puts nodes and relationships in the same column, but the context from the first match is lost in the second half.
So how can I return all matched nodes and relationships as one minimal list?
UPDATE:
This is the final modified version of the answer query I am using
MATCH (n:TEST)
OPTIONAL MATCH (n)-[r]->()
RETURN n {.*, rels:collect(r {properties:properties(r), id:id(r), type:type(r), startNode:id(startNode(r)), endNode:id(endNode(r))})} as n
There are a couple ways to handle this, depending on if you want to hold these within lists, or within maps, or if you want a map projection of a node to include its relationships.
If you're using Neo4j 3.1 or newer, then map projection is probably the easiest approach. Using this, we can output the properties of a node and include its relationships as a collected property:
MATCH (n:TEST)
OPTIONAL MATCH (n)-[r]->()
RETURN n {.*, rels:collect(r)} as n
Here's what you might do if you wanted each row to be its own pairing of a node and a single one of its relationships as a list:
...
RETURN [n, r] as pair
And as a map:
...
RETURN {node:n, rel:r} as pair
EDIT
As far as returning more data from each relationship, if you check the Code results tab, you'll see that the id, relationship type, and start and end node ids are included, and accessible from your back-end code.
However, if you want to explicitly return this data, then we just need to include it in the query, using another map projection for each relationship:
MATCH (n:TEST)
OPTIONAL MATCH (n)-[r]->()
RETURN n {.*, rels:collect(r {.*, id:id(r), type:type(r), startNode:startNode(r), endNode:endNode(r)})} as n
I have the following example cypher:
MATCH (n)
OPTIONAL MATCH (n)-[:likes]->(p)
RETURN n, p, label(p)
This works great if optional match return a non null value. However if optional match is empty, this fails. Is there a way to return label(p) if p exists else return null?
First things, I think you probably want to narrow down what n matches with some criteria and an index, but to answer your question, coalesce is your friend.
MATCH (n)
OPTIONAL MATCH (n)-[:likes]->(p)
RETURN n
, coalesce(p, 'nobody')
, coalesce(labels(p),'nothing')
I'm playing with cypher and I have some simple aggregation going on for me.
MATCH (p:Person)-[:HAS_CAR]->(n:Car)
RETURN n, count(p)
MATCH (p:Person)-[:HAS_APARTMENT]->(n:Apartment)
RETURN n, count(p)
MATCH (p:Person)-[:HAS_HOUSE]->(n:House)
RETURN n, count(p)
The problem is that I have to make 3 trips to the database to get all those results together. The problematic thing about that is that those queries are the last MATCH statement in a much bigger chain. Like this:
MATCH (:City { Id: 10})<-[:LIVES_IN]-(p:Person)
WITH p
MATCH ...
WITH p
MATCH ...
WITH p
MATCH ...
WITH p
MATCH ...
WITH p
MATCH p-[:HAS_CAR]->(n:Car)
RETURN n, count(p)
After all those MATCH ... WITH statements, only a few person nodes are matched so the last part of the query is very fast, but the initial part is not. I can't help but think that this could be improved because all three queries share a lot of statements.
I came up with this:
...
MATCH p-[:HAS_CAR|HAS_APARTMENT|HAS_HOUSE]->(n)
RETURN n, labels(n), count(p)
And I can work with that. But what if I wanted to mix in something like this:
MATCH p-[:KNOWS]->(:Person)-[:HAS_BIKE]->(n:Bike)
RETURN n, count(p)
Or even:
MATCH p-[:KNOWS]->(:Person)-[:HAS_BIKE|HAS_BOAT]->(n)
RETURN n, labels(n), count(p)
Can all of this be done in a single query and how?
Sometimes you need to use collections instead of rows to merge aggregation queries together and pass them along. This strategy might help... For example:
MATCH (p:Person)-[:HAS_CAR]->(car:Car)
WITH car, count(p) carCount
WITH collect({car:car, count:carCount}) as carCounts
MATCH (p:Person)-[:HAS_APARTMENT]->(n:Apartment)
WITH n, count(p) as apartmentCount, carCounts
RETURN collect({apartment:n, count:apartmentCount}) as apartmentCounts, carCounts
Update (see comments)--this lets you pass along the results of a filter and do a quick id lookup to find them again:
MATCH (p:Person)
WHERE p.name = "John" // or whatever else you need to filter on
WITH collect(id(p)) as pids
MATCH (p)-[:HAS_CAR]->(car:Car)
WHERE id(p) IN pids
WITH car, count(p) carCount, pids
WITH collect({car:car, count:carCount}) as carCounts, pids
MATCH (p)-[:HAS_APARTMENT]->(n:Apartment)
WHERE id(p) IN pids
WITH n, count(p) as apartmentCount, carCounts
RETURN collect({apartment:n, count:apartmentCount}) as apartmentCounts, carCounts
I'm new to neo4j and would really appreciate your help for this.
I have following graph created in neo4j.
n1----n2----n3----n4---n5
n1,n2,n3,n4,n5 all are nodes
--- : relationship_type_1 (REL)
Now given any set of nodes (in any order), I want to check whether these nodes are connected or not.
E.g. Given n1, n2, n3 ==> Connected.
Given n1, n3, n2, n4, n5 ==> Connected.
How should I formulate my cypher query to check connectivity?
Following query is working even if I change the order,
MATCH p=_1--_2--_3
WHERE _1.name?="Node1" and ALL (n in nodes(p)
WHERE n.name IN ["Node1", "Node2", "Node4"])
RETURN nodes(p);
on http://console.neo4j.org/?id=xl8pnl
but if I provide start nodes instead of using _1,_2 and change the order then it's not returning me the path. :(
http://console.neo4j.org/?id=xl8pnl
for following query,
START p1=node(6),p2=node(5),p3=node(4) MATCH p=p1--p2--p3
WHERE p1.name?="Node1" AND ALL (n IN nodes(p) WHERE n.name IN ['Node1' ,'Node3', 'Node2' , 'Node4'])
RETURN nodes(p)
it doesn't return the path as nodes are connected in node(6)-node(5)-node(4) order.
You need to list the different patterns that constitute the "connectedness" to you for instant by listing them explicitly like
console.neo4j.org/r/2w3poz
START p1=node(0),p2=node(4),p3=node(5)
RETURN
CASE
WHEN p1--p2--p3 OR p2--p1--p3 OR p1--p3--p2 OR p3--p2--p1 OR p3--p1--p2
THEN 'Connected'
ELSE 'Not connected'
END
Case 1:
2 paths found
MATCH p=_1--_2--_3--_4
WHERE _1.name?="Node1" and
ALL (n in nodes(p)
WHERE n.name IN ["Node1", "Node2", "Node3", "Node4"])
RETURN nodes(p);
Check it out here:
http://console.neo4j.org/?id=nn9yl6
in this case order dosen't matter
Case 2
(no path found)
Use node 1,2,4
MATCH p=_1--_2--_3
WHERE _1.name?="Node1" and ALL (n in nodes(p)
WHERE n.name IN ["Node1", "Node2", "Node4"])
RETURN nodes(p);
Check it out here:
http://console.neo4j.org/?id=xl8pnl