I'd like to perform a check on a property that exists on both nodes and relationships in my DB. Is there any way to aggregate them all as entity and then perform the check on entity instead of performing three separate checks?
What I currently have is:
MATCH (n1)-[r]-(n2) WHERE (myConditions)
WITH n1, r, n2
WHERE n1.property=1 AND r.property=1 AND n2.property=1
RETURN *
What I'm looking for is something like:
MATCH (n1)-[r]-(n2) WHERE (myConditions)
WITH n1, r, n2 AS entity
WHERE entity.property=1
RETURN *
Important note: There are queries with more than 2 nodes and more than one relationships. I would like to aggregate all graph entities and then perform a single check.
By the way, if "aggregation" is not the right term for this case, please feel free to correct me.
You could use predicates like all(), any(), none() etc. on all nodes and relationships in your path. You still have to check for nodes and relationships separately.
MATCH path=(n1)-[r]-(n2)
WHERE (myConditions)
WITH path
WHERE all(n in nodes(path) WHERE n.property = 1)
AND all(r in relationships(path) WHERE r.property = 1)
RETURN path
Related
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
I have a one direction tree as described as:
Node_C [is_a_method_of] Node_A
Node_D [is_related_to] Node_B
Node_C [is_related_to] Node_D
Node_A and Node_B are root nodes because they are not related or are a method of other nodes. How can I return them?
I saw in another post:
MATCH (n)
WHERE NOT (n)--()
RETURN n;
But that returns orphan nodes.
You would probably want to add some relationship type and direction to your query:
MATCH (n)
WHERE NOT (n)-[:is_a_method_of]->() AND NOT (n)-[:is_related_to]->()
RETURN n;
You haven't really specified the direction of relationships in your graph, so this is only my assumption. You could adapt this query to work on your graph schema if my assumptions are wrong.
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;
I have got a set of nodes and I would like to write a query to find every relationships which exist between these nodes.
Any recommendation?
My first attemp would be a MATCH a-[rel]-b WHERE... and my WHERE clause would be a OR of all the ids I have in my set of nodes.
Any better idea?
In these answers, I assume you will pass the ID list as a parameter named ids.
If you want to exclude relationships from a node to itself:
MATCH (a)-[r]-(b)
WHERE id(a) IN {ids} AND id(b) IN {ids} AND a <> b
RETURN r;
If you want to include relationships from a node to itself:
MATCH (a)-[r]-(b)
WHERE id(a) IN {ids} AND id(b) IN {ids}
RETURN r;
You could do something like this:
MATCH (a)-[rel]-()
WHERE ID(a) IN {node_ids}
RETURN rel, ID(rel), type(rel), ID(startNode(rel)), ID(endNode(rel))
Here you'd be passing in a node_ids parameter which would be an array.
Note also that using internal Neo4j IDs for long-term reference to nodes may break if Neo4j defragments the nodes.
I'm struggling to find a single clean, efficient Cypher query that will let me identify all distinct paths emanating from a start node such that every relationship in the path is of the same type when there are many relationship types.
Here's a simple version of the model:
CREATE (a), (b), (c), (d), (e), (f), (g),
(a)-[:X]->(b)-[:X]->(c)-[:X]->(d)-[:X]->(e),
(a)-[:Y]->(c)-[:Y]->(f)-[:Y]->(g)
In this model (a) has two outgoing relationship types, X and Y. I would like to retrieve all the paths that link nodes along relationship X as well as all the paths that link nodes along relationship Y.
I can do this programmatically outside of cypher by making a series of queries, the first to
retrieve the list of outgoing relationships from the start node, and then a single query (submitted together as a batch) for each relationship. That looks like:
START n=node(1)
MATCH n-[r]->()
RETURN COLLECT(DISTINCT TYPE(r)) as rels;
followed by:
START n=node(1)
MATCH n-[:`reltype_param`*]->()
RETURN p as path;
The above satisfies my need, but requires at minimum 2 round trips to the server (again, assuming I batch together the second set of queries in one transaction).
A single-query approach that works, but is horribly inefficient is the following single Cypher query:
START n=node(1)
MATCH p = n-[r*]->() WHERE
ALL (x in RELATIONSHIPS(p) WHERE TYPE(x) = TYPE(HEAD(RELATIONSHIPS(p))))
RETURN p as path;
That query uses the ALL predicate to filter the relationships along the paths enforcing that each relationship in the path matches the first relationship in the path. This, however, is really just a filter operation on what it essentially a combinatorial explosion of all possible paths --- much less efficient than traversing a relationship of a known, given type first.
I feel like this should be possible with a single Cypher query, but I have not been able to get it right.
Here's a minor optimization, at least non-matching the paths will fail fast:
MATCH n-[r]->()
WITH distinct type(r) AS t
MATCH p = n-[r*]->()
WHERE type(r[-1]) = t // last entry matches
RETURN p AS path
This is probably one of those things that should be in the Java API if you want it to be really performant, though.