I would like to do a search, and I would like to start traversing from 2 labels (OR condition). For example, I need to find out all the nodes which have labels either 'Male' or 'Female' and whose property, name =~ '.ail.'.
8 Answers
You can put this condition in the WHERE
clause:
MATCH (n)
WHERE n:Male OR n:Female
RETURN n
EDIT
As @tbaum points out this performs an AllNodesScan
. I wrote the answer when labels were fairly new and expected the query planner to eventually implement it with a NodeByLabelScan
for each label, as it does for the single label case
MATCH (n)
WHERE n:Male
RETURN n
I still think this is a reasonable expression of the query and that it is reasonable to expect the query planner to implement it with label scans, but as of Neo4j 2.2.3 the query is still implemented with an AllNodesScan
and a label filter. Here is therefore a more verbose alternative. Since the label disjunction signifies a set union and this union can be expressed in different ways, we can express it in a way that the query planner implements without scanning all nodes, and instead starts with a NodeByLabelScan
per label.
MATCH (n:Male)
WHERE n.name =~ '.ail.'
RETURN n
UNION MATCH (n:Female)
WHERE n.name =~ '.ail.'
RETURN n
This means expressing the query once for each label and joining them with an explicit UNION
. This is not unreasonable, at least for smaller number of labels, but it's not clear to me why the query planners shouldn't be able to infer the same implementation from the simpler query so I have opened a github issue here.

- 4,922
- 4
- 42
- 74

- 9,844
- 34
- 34
-
10Is there a shorter way to do this ? For e.g. for relationships you can specify `( n )-[: rel1 | rel2 ]->(m)` where ` | ` indicates `OR` – Lyman Zerga Apr 22 '15 at 22:36
-
No, you cannot use a that pattern for labels and I am not aware of any other pattern that is shorter or that works without a `WHERE` clause. Feel free to submit a feature request at the Neo4j [github repository](https://github.com/neo4j/neo4j/issues). – jjaderberg Jul 20 '15 at 09:04
-
@Lyman Zerga i also searched at many places but having nothing like that – Ravinder Payal Oct 14 '15 at 14:45
-
1I just ran into the same issue and solved it using the MATCH n WHERE n:Label1 OR n:Label2 approach. Based on what got returned from running EXPLAIN and PROFILE for my query, it looks like an `AllNodesScan` is not being performed. In my case, I had two labels, there were two node scans, and the results were unioned. So, it would seem the first solution is now probably the best one. – augustearth Mar 12 '18 at 20:09
-
Can somebody confirm @augustearth statement? I'm a novice to neo4j and don't know how to count the number of scans and judge the performance differences – Daniel May 22 '18 at 13:58
-
As an update this no longer performs an AllNodesScan and instead performs two NodeByLabelScan along with a Union and a Distinct – Simon Thordal Sep 11 '20 at 08:22
MATCH n WHERE n:Label1 OR n:Label2
... will result in an AllNodesScan this is a bad Idea!
maybe a better solution:
OPTIONAL MATCH (n1:Label1)
WITH collect(distinct n1) as c1
OPTIONAL MATCH (n2:Label2)
WITH collect(distinct n2) + c1 as c2
OPTIONAL MATCH (n3:Label3)
WITH collect(distinct n3) + c2 as c3
UNWIND c3 as nodes
RETURN count(nodes),labels(nodes)

- 226
- 2
- 5
-
4
-
1Thanks for pointing out the `AllNodesScan`, I thought that would have been resolved by now. I have updated my answer, do you have any thoughts about my more verbose alternative using `UNION` and how it compares to your `OPTIONAL MATCH`/`collect()`/`UNWIND`? – jjaderberg Jul 20 '15 at 09:08
-
1One note: UNION is inconvenient (and in some cases unusable) because currently (2.2) you can't do any processing with the results of the UNION. For example, you can't use SKIP/LIMIT or COUNT. – Jonathan Crosmer Aug 03 '15 at 14:02
With Neo4j 3.4.7 the query planner does a UNION and then a DISTINCT of 2 NodeByLabelScan
s when you hand it a WHERE query with 2 OR'ed label filters. Trying the sandbox Offshore Leaks Database with EXPLAIN MATCH (o) WHERE o:Officer OR o:Entity RETURN o
yields this planning:

- 135
- 1
- 7
As for v3.5, we can do:
MATCH (n) WHERE (n:User OR n:Admin) AND n.name CONTAINS "ail" RETURN n
and get:
╒══════════════════╕
│"n" │
╞══════════════════╡
│{"name":"Abigail"}│
├──────────────────┤
│{"name":"Bailee"} │
└──────────────────┘

- 103
- 1
- 7
If you want to filter node by multiple labels with OR or IN condition, use this code:
MATCH (n)
WHERE labels(n) in [['Male'],['Female']]
AND n.name =~ '.ail.'
RETURN n

- 81
- 1
- 2
There is a dedicated way to match on multiple labels now (in 2023).
This will only work on Neo4j 5 and higher.
MATCH (n:Movie|Person) RETURN n.name AS name, n.title AS title
As per the docs found here.
To solve your specific query:
MATCH (n:User|Admin) WHERE n.name CONTAINS "ail" RETURN n

- 3,704
- 2
- 25
- 36

- 520
- 7
- 15
Another option, if you need to work with the combined set or otherwise avoid the UNION:
MATCH(m:Male) WHERE m.name=~'.ail.' WITH COLLECT(m) AS male
MATCH(f:Female) WHERE f.name=~'.ail.' WITH male, COLLECT(f) AS female
UNWIND (male + female) AS person
RETURN person.name;
This is not quite as efficient as the UNION approach, but still avoids the expensive AllNodesScan operator. In my use case, the query already contains a UNION for a different purpose.

- 3,917
- 4
- 17
- 22
Documentation for v3.0 says this:
One can also describe a node that has multiple labels:
(a:User:Admin)-->(b)
Source: https://neo4j.com/docs/developer-manual/current/cypher/#_labels

- 1
- 1

- 31
- 1
-
1The answer is not correct but is not completely bad, I think the author just missed to include the relationship in the query but it works for the purpose of matching multiple node labels: `MATCH (a:User:Admin)-[r]->(b) return a,r,b` – artemisian Jan 06 '17 at 11:56
-
FYI. The Source URL changed a little. This is the new one: https://neo4j.com/docs/developer-manual/current/cypher/syntax/patterns/#_labels – Chad Mar 18 '17 at 23:54
-
28Actually, this is wrong, (a:User:Admin) this query describes when a node is a "User and also Admin" No a user OR Admin. – Carlos_Mondragon Apr 17 '17 at 23:19