How do I find disconnected nodes on neo4j with Cypher? - neo4j

I am toying with neo4j and noticed that all Cypher queries need a starting point in the START clause.
I was wondering how can I find all disconnected nodes using Cypher ?
thanks

If all your nodes are indexed (e.g. via auto-indexing) you could use an index query as a start point and then find those nodes that have no outgoing relationships.
start n=node:node_auto_index("id:*")
match n-[r?]->m
where r is null
return n
Nowadays I would rather use:
start n=node:node_auto_index("id:*")
where not (n-->m)
return n

With Neo4j v3.0+ I just use;
MATCH (n)
WHERE NOT (n)--()
RETURN n
(or variations thereof). The query is reasonably fast.

I use something like this, but only when I'm using spring-data-neo4j:
start n = node:__types__(className="com.app.entity.Model")
// match, where...
return n
Hope that helps!

You can't. Graph global queries are not possible with todays Cypher.

Related

Finding nodes not matching query in cypher

We have build up a NEO4j database with sample network data in it. We are currently trying to find a query to find NOT matching nodes.
We have 10 nodes in database and we get 8 of them by using the following query:
match(n:nodeType)-[r:binded]-(m.nodetype2)-[z:binded]-(t:nodeType) where n.workingMode='Working' and t.workingMode='Protection' return n
What we want is finding the two nodes which does not satify above condition.
I have found some entires mentioning the usage of NOT x IN y and tried a few solutions including
match(a) where a.workingMode ='Working'
match(n:nodeType)-[r:binded]-(m.nodetype2)-[z:binded]-(t:nodeType) where n.workingMode='Working' and t.workingMode='Protection'
and NOT a.id IN n.id
return a
but that returns 10 and others i have tried provided either 10 or 0 results.
Thanks in advance
You can pass the result of your first statement to the second statement of the query as a list and then use NOT IN to exclude these nodes:
MATCH(n:nodeType)-[r:binded]-(m.nodetype2)-[z:binded]-(t:nodeType)
WHERE n.workingMode='Working' AND t.workingMode='Protection'
WITH collect(n) as ns
MATCH (a:nodeType)
WHERE a.workingMode ='Working' AND NOT a IN ns
RETURN a

simple match query taking ages

I have a simple query
MATCH (n:TYPE {id:123})<-[:CONNECTION*]<-(m:TYPE) RETURN m
and when executing the query "manually" (i.e. using the browser interface to follow edges) I only get a single node as a result as there are no further connections. Checking this with the query
MATCH (n:TYPE {id:123})<-[:CONNECTION]<-(m:TYPE)<-[n:CONNECTION]-(o:TYPE) RETURN m,o
shows no results and
MATCH (n:TYPE {id:123})<-[:CONNECTION]<-(m:TYPE) RETURN m
shows a single node so I have made no mistake doing the query manually.
However, the issue is that the first question takes ages to finish and I do not understand why.
Consequently: What is the reason such trivial query takes so long even though the maximum result would be one?
Bonus: How to fix this issue?
As Tezra mentioned, the variable-length pattern match isn't in the same category as the other two queries you listed because there's no restrictions given on any of the nodes in between n and m, they can be of any type. Given that your query is taking a long time, you likely have a fairly dense graph of :CONNECTION relationships between nodes of different types.
If you want to make sure all nodes in your path are of the same label, you need to add that yourself:
MATCH path = (n:TYPE {id:123})<-[:CONNECTION*]-(m:TYPE)
WHERE all(node in nodes(path) WHERE node:TYPE)
RETURN m
Alternately you can use APOC Procedures, which has a fairly efficient means of finding connected nodes (and restricting nodes in the path by label):
MATCH (n:TYPE {id:123})
CALL apoc.path.subgraphNodes(n, {labelFilter:'TYPE', relationshipFilter:'<CONNECTION'}) YIELD node
RETURN node
SKIP 1 // to avoid returning `n`
MATCH (n:TYPE {id:123})<-[:CONNECTION]<-(m:TYPE)<-[n:CONNECTION]-(o:TYPE) RETURN m,o Is not a fair test of MATCH (n:TYPE {id:123})<-[:CONNECTION*]<-(m:TYPE) RETURN m because it excludes the possibility of MATCH (n:TYPE {id:123})<-[:CONNECTION]<-(m:ANYTHING_ELSE)<-[n:CONNECTION]-(o:TYPE) RETURN m,o.
For your main query, you should be returning DISTINCT results MATCH (n:TYPE {id:123})<-[:CONNECTION*]<-(m:TYPE) RETURN DISTINCT m.
This is for 2 main reasons.
Without distinct, each node needs to be returned the number of times for each possible path to it.
Because of the previous point, that is a lot of extra work for no additional meaningful information.
If you use RETURN DISTINCT, it gives the cypher planner the choice to do a pruning search instead of an exhaustive search.
You can also limit the depth of the exhaustive search using ..# so that it doesn't kill your query if you run against a much older version of Neo4j where the Cypher Planner hasn't learned pruning search yet. Example use MATCH (n:TYPE {id:123})<-[:CONNECTION*..10]<-(m:TYPE) RETURN m

Neo4J, Match node with "OR"

Helo,
i want to match a graph where a node can be typeX or typeY
my first thought was:
match (:typeX|typeY)-[]-(z) return z
But this doesn´t work :(
Is there any way without typing the query twice?
Like this:
match (:typeX)-[]-(z), (:typeY)-[]-(z) return z
Can someone help me?
thank you in advance :)
One way is
MATCH (n) WHERE labels(n) IN ['typeX','typeY']
WITH n
MATCH (n)-[]-(z)
RETURN z
However, if "either typeX or typeY" are queried frequently and share some common purpose in your domain, you could add another common label to them like "commonXY" and query using that label instead.
Unfortunately there's not a good efficient way to do this without sacrificing performance. All other current answers are forced to scan all nodes and then filter on their labels, which isn't performant with large numbers of nodes (PROFILE the queries). All the efficient means I know of are more verbose.
You can perform a UNION of the two queries to return nodes one hop from all :typeX and :typeY nodes.
match (:typeX)--(z)
return z
union
match (:typeY)--(z)
return z
This query will work even if n has multiple labels:
MATCH (n)
WHERE ANY(lab IN labels(n) WHERE lab IN ['typeX', 'typeY'])
MATCH (n)--(z)
RETURN z
there is a n predicate n:Label
MATCH (n)--(z)
WHERE n:typeX OR n:typeY
RETURN z

What is the appropriate cypher query?

I am trying to run the web ui on
7474/webadmin/#
Suppose I want to find a node that has a property "title" with a value of "Home".
How do I find that node using a cypher query? (There should be only one node.)
Also, suppose I want to retrieve a relationship?
Let's say I have the following:
A -entitledTo-> B -entitledTo-> C
I have already tried the following:
start n=node(*) where n.title='Home' return n;
start c=node(node_c_id) match a-[:entitledTo]->b-[:entitledTo]->c return a,b,c;
However, I get this error message: The property 'title' does not exist on Node[0]
How do I resolve this issue?
Lastly, this is version 2.0.0-M03
use:
start n=node(*) where has(n.title) and n.title='Home' return n
In general you should consider using indexes for this kind of operation, Neo4j's reference manual has lots of information about this.
You can use:
start n=node(*) where n.title! ='Home' return n;
See the section on missing properties in where clauses
To retrieve the Relationships, perhaps the Cypher PATH command could be usefull.

How to return only the end/leaf nodes in a Neo4j cypher query?

I have a structure like so:
user-[:talking]->topic-[:categorized_in]->topic[:categorized_in]->topic... etc
Starting at a user, how would I get the furthest away topics they're talking about. Basically this represents the top level categories they are talking about. This is the only way I know to go about doing this, and it returns all of the nodes along the way, not just the leaf nodes.
START user=node(1)
MATCH user-[:talking]->x<-[:categorized_in*0..]-y
RETURN distinct y.uuid
This is my latest attempt. It seems to work, though I don't know if this is the best way to go about it?:
START user=node(1)
MATCH user-[:talking]->x<-[:categorized_in*0..]-y<-[?:pull]-z
WHERE z is null
RETURN distinct y.uuid
So this is how to do it for anybody interested:
START user=node(1)
MATCH user-[:talking]->x<-[:categorized_in*0..]-y<-[?:categorized_in]-z
WHERE z is null
RETURN distinct y.uuid
You can now filter against patterns in the WHERE.
So if you have a newer version of Neo4j, I think the query would look like
START user=node(1)
MATCH user-[:talking]->x<-[:categorized_in*0..]-y
WHERE NOT(y<-[:categorized_in]-())
RETURN DISTINCT y.uuid

Resources