Neo4j Match multiple labels - neo4j

There is the situation in which i need to match any one of the label of node.
We can do it for relationship types like
(n)-[:KNOWS|LOVES]->(m)
Can we match node labels like this?
eg.
MATCH (c:computer)<-[:belongs_to]-(comp:HP|IBM)
return comp
Currently I have tried this and it gives results, Is there any simpler way?
MATCH (c:computer)<-[:belongs_to]-(comp)
WHERE 'HP' IN labels(comp) OR 'IBM' IN labels(comp)
return comp

I Think
WHERE 'HP' IN labels(comp) OR 'IBM' IN labels(comp)
AND
WHERE comp:HP OR comp:IBM
Will work with same manner second one is simple to use

This form of your last query is at least simpler to write and more easily understood:
MATCH (c:computer)<-[:belongs_to]-(comp)
WHERE comp:HP OR comp:IBM
return comp;

Currently facing this same problem.
Since I have quite a few labels to match on (revealing a bit of a flaw in my architecture!) I found the following to solve this problem concisely:
MATCH (n:computer)
WHERE any(label in labels(n) WHERE label in ['HP', 'IBM'])
RETURN n

Related

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

Excluding label names in simple Neo4j Query

Usually I can find everything I need already on SO but not this time. I'm looking for a very simple way to exclude labels, for example (pseudo code):
match (n) where n not in (Label1, Label2) return n
Sorry about crappy query. In short I have labels x,y,z and I want to return all of them apart from z.
Thnx!
This should do it:
MATCH (n)
WHERE NOT n:Label1 AND NOT n:Label2
RETURN n;
If you have a long list of labels you want to exclude, I find this syntax to be helpful:
match (n)
where not labels(n) in [['label1'],['label2'],['label3']]

Cypher query: return empty result when adding one match twice

The query as followings and get empty result. When I remove person-[:TEACH]-lesson, it works fine. Anybody can tell me what is the reason? Cheers
start person=node(1)
match person-[:TEACH|LEARN]-lesson,
person-[:TEACH]-lesson
return person,lesson
You probably don't have a TEACH relation between person and lesson.
match person-[:TEACH|LEARN]-lesson,
person-[:TEACH]-lesson
is match person-[:TEACH|LEARN]-lesson AND match person[:TEACH]-lesson, which is a repetition anyway.
start person=node(1)
match person-[:TEACH|LEARN]-lesson
return person,lesson
will work if you want to match TEACH or LEARN (as long as at least one of them exists, you'll get a result).

Combine nodes from more MATCHes into single variable

Using neo4j community edition 2.x. In Cypher, I need to MATCH nodes in (two) different ways, then combine these (two) sets of matched nodes into single set (one variable name). This set would then be used for further action.
naive graph example (I can't post images)
I would like to find all knowledge of the squirrel, including the knowledge shared by the groups she is member of. (example is fictional)
I imagine something like this:
MATCH (u:User{username:'squirrel'}), (:User{username:'squirrel'})<-[:MEMBER]-(g:Group)
WITH "COMBINATION OF u AND g" AS ug
MATCH (ug)-[:KNOW_HOW]->(k:Knowledge)
RETURN k.type
Outcome should be both "crack nuts" and "escape predators".
In the place of "COMBINATION OF u AND g" I tried variations on collect(u)+collect(g), EXTRACT, etc. Without success.
So far the simplest working way I found is using UNION.
MATCH (u:User{username:'squirrel'})-[:KNOW_HOW]->(k:Knowledge)
RETURN k.type
UNION
MATCH (u:User{username:'squirrel'})<-[:MEMBER]-(:Group)-[:KNOW_HOW]->(k:Knowledge)
RETURN k.type
This might solve this simple example, but is not good for more complex queries. I seek the solution for more general problem: MATCH several sets of nodes, glue them into single set (single variable) and continue with this new set.
Any ideas, please? Am I missing something basic? Or is this impossible? Thanks!
Something possibly similar on grokbase.
edit:
With this hacky solution to similar question I was able to solve the problem by extracting internal ids from collection of nodes:
MATCH (u:User{username:'squirrel'}), (:User{username:'squirrel'})<-[:MEMBER]-(g:Group)
WITH [x in collect(u)+collect(g)|id(x)] as collectedIds MATCH (ug) WHERE id(ug) in collectedIds
MATCH (ug)-[:KNOW_HOW]->(k:Knowledge)
RETURN k.type
Could it be done any better?
At least since Neo4j 3.0 you can use variable-length pattern matching to solve this issue. Simply set explicitly the minimum length to 0 and move the label test to a separate WHERE clause:
MATCH (:User {username:'squirrel'}) <-[:MEMBER*0..1]- (ug)
WHERE ug:User OR ug:Group
WITH ug
MATCH (ug)-[:KNOW_HOW]->(k:Knowledge)
RETURN k.type
Not sure about the general case, but for this specific case, you might try to combine the two patterns into one as follows,
MATCH (u:User{username:'squirrel'})<-[:MEMBER*0..1]-()-[:KNOW_HOW]->(k:Knowledge)
RETURN k.type
The only general solution I found so far:
match required starting points (with different names)
collect internal ids of starting points
match the starting points with collected ids (now the starting points have single name)
do whatever action you need to do with the starting points
Now the code itself:
MATCH (u:User{username:'squirrel'}), (:User{username:'squirrel'})<-[:MEMBER]-(g:Group)
WITH [x in collect(u)+collect(g)|id(x)] as collectedIds MATCH (ug) WHERE id(ug) in collectedIds
MATCH (ug)-[:KNOW_HOW]->(k:Knowledge)
RETURN k.type

Match several node property values in Cypher / Neo4J

using Cypher 2 I want to find all the nodes of a certain label (Context), which are called either "health" or "opinion".
The query that works is:
MATCH (c:Context) WHERE c.name="health" OR c.name="opinion" RETURN c;
But I'm wondering if Cypher has a syntax that I could put it into the first MATCH part, something like this:
MATCH (c:Context{name:"health"|name:"opinion})
The example above doesn't work, but I'm just showing it to let you know what I mean.
Thank you!
Alternatively, you can do this:
MATCH (c:Context) WHERE c.name IN ['health', 'opinion'] RETURN c
Still not in the "MATCH" statement, but a little easier as your list of possible values grows.
You could do
MATCH (c:Context {name:"health"}), (d:Context { name:"opinion"})
RETURN c,d

Resources