Node and relationship matching¶
The py2neo.matching
module provides functionality to match nodes
and relationships according to certain criteria. For each entity type,
a Matcher
class and a Match
class are provided. The Matcher
can be used to perform a basic selection, returning a Match
that
itself can be evaluated or further refined.
The underlying query is only evaluated when the selection undergoes
iteration or when a specific evaluation method is called (such as
NodeMatch.first()
). This means that a NodeMatch
object may be reused before and after data changes for different
results.
Node matching¶
NodeMatcher
objects¶
- class py2neo.NodeMatcher(graph)[source]¶
Matcher for selecting nodes.
A
NodeMatcher
can be used to locate nodes that fulfil a specific set of criteria. Typically, a single node can be identified passing a specific label and property key-value pair. However, any number of labels and predicates supported by the Cypher WHERE clause are allowed.For a simple equality match by label and property:
>>> from py2neo import Graph >>> from py2neo.matching import * >>> g = Graph() >>> nodes = NodeMatcher(g) >>> keanu = nodes.match("Person", name="Keanu Reeves").first() >>> keanu Node('Person', born=1964, name='Keanu Reeves')
- Parameters:
graph –
Graph
object on which to perform matches
- iter(matcher)
Iterate through the matches, yielding the node ID for each one in turn.
- len(matcher)
Count the matched nodes and return the number matched.
- node_id in matcher
Determine whether a given node ID exists.
- matcher[node_id]
Match and return a specific node by ID. This raises a
KeyError
if no such node can be found.
- get(identity)[source]¶
Create a new
NodeMatch
that filters by identity and returns the first matchedNode
. This can be used to match and return aNode
by ID.>>> matches.get(1234) Node('Person', name='Alice')
If no such
Node
is found,None
is returned instead. Contrast withmatcher[1234]
which raises aKeyError
if no entity is found.
NodeMatch
objects¶
- class py2neo.NodeMatch(graph, labels=frozenset({}), predicates=(), order_by=(), skip=None, limit=None)[source]¶
Immutable set of node selection criteria.
- iter(match)
Iterate through all matching nodes.
- len(match)
Return the number of nodes matched.
- all()[source]¶
Evaluate the selection and return a list of all matched
Node
objects.- Returns:
list of matching
Node
objects
New in version 2020.0.
- count()[source]¶
Evaluate the selection and return a count of the number of matches.
- Returns:
number of nodes matched
New in version 2020.0.
- exists()[source]¶
Evaluate the selection and return
True
if at least one matched node exists.- Returns:
boolean indicating presence or absence of a match
New in version 2020.0.
- first()[source]¶
Evaluate the match and return the first
Node
matched orNone
if no matching nodes are found.- Returns:
a single matching
Node
orNone
- limit(amount)[source]¶
Limit to at most amount nodes.
- Parameters:
amount – maximum number of nodes to return
- Returns:
refined
NodeMatch
object
- order_by(*fields)[source]¶
Order by the fields or field expressions specified.
To refer to the current node within a field or field expression, use the underscore character
_
. For example:match.order_by("_.name", "max(_.a, _.b)")
- Parameters:
fields – fields or field expressions to order by
- Returns:
refined
NodeMatch
object
- skip(amount)[source]¶
Skip the first amount nodes in the result.
- Parameters:
amount – number of nodes to skip
- Returns:
refined
NodeMatch
object
- where(*predicates, **properties)[source]¶
Refine this match to create a new match. The criteria specified for refining the match consist of predicates and properties. Conditions are individual Cypher expressions that would be found in a WHERE clause; properties are used as exact matches for property values.
To refer to the current node within a predicate expression, use the underscore character
_
. For example:match.where("_.name =~ 'J.*'")
Simple property equalities can also be specified:
match.where(born=1976)
- Parameters:
predicates – Cypher expressions to add to the WHERE clause
properties – exact property match keys and values
- Returns:
refined
NodeMatch
object
Relationship matching¶
RelationshipMatcher
objects¶
- class py2neo.RelationshipMatcher(graph)[source]¶
Matcher for selecting relationships that fulfil a specific set of criteria.
- Parameters:
graph –
Graph
object on which to perform matches
- iter(matcher)
Iterate through the matches, yielding the relationship ID for each one in turn.
- len(matcher)
Count the matched relationships and return the number matched.
- relationship_id in matcher
Determine whether a given relationship ID exists.
- matcher[relationship_id]
Match and return a specific relationship by ID. This raises a
KeyError
if no such relationship can be found.
- get(identity)[source]¶
Create a new
RelationshipMatch
that filters by identity and returns the first matchedRelationship
. This can be used to match and return aRelationship
by ID.>>> relationships.get(1234) Relationship(...)
If no such
Relationship
is found,None
is returned instead. Contrast with matcher[1234] which raises aKeyError
if no entity is found.
- match(nodes=None, r_type=None, **properties)[source]¶
Describe a basic relationship match using start and end nodes plus relationship type.
- Parameters:
nodes – Sequence or Set of start and end nodes (
None
means any node); a Set implies a match in any directionr_type –
properties – set of property keys and values to match
- Returns:
RelationshipMatch
instance
RelationshipMatch
objects¶
- class py2neo.RelationshipMatch(graph, nodes=None, r_type=None, predicates=(), order_by=(), skip=None, limit=None)[source]¶
Immutable set of relationship selection criteria.
- iter(match)
Iterate through all matching relationships.
- len(match)
Return the number of relationships matched.
- all()[source]¶
Evaluate the selection and return a list of all matched
Relationship
objects.- Returns:
list of matching
Relationship
objects
New in version 2020.0.
- count()[source]¶
Evaluate the selection and return a count of the number of matches.
- Returns:
number of relationships matched
New in version 2020.0.
- exists()[source]¶
Evaluate the selection and return
True
if at least one matched relationship exists.- Returns:
boolean indicating presence or absence of a match
New in version 2020.0.
- first()[source]¶
Evaluate the selection and return the first
Relationship
selected orNone
if no matching relationships are found.- Returns:
a single matching
Relationship
orNone
- limit(amount)[source]¶
Limit to at most amount relationships.
- Parameters:
amount – maximum number of relationships to return
- Returns:
refined
RelationshipMatch
object
- order_by(*fields)[source]¶
Order by the fields or field expressions specified.
To refer to the current relationship within a field or field expression, use the underscore character
_
. For example:match.order_by("_.weight", "max(_.a, _.b)")
- Parameters:
fields – fields or field expressions to order by
- Returns:
refined
RelationshipMatch
object
- skip(amount)[source]¶
Skip the first amount relationships in the result.
- Parameters:
amount – number of relationships to skip
- Returns:
refined
RelationshipMatch
object
- where(*predicates, **properties)[source]¶
Refine this match to create a new match. The criteria specified for refining the match consist of predicates and properties. Conditions are individual Cypher expressions that would be found in a WHERE clause; properties are used as exact matches for property values.
To refer to the current relationship within a predicate expression, use the underscore character
_
. For example:match.where("_.weight >= 30")
Simple property equalities can also be specified:
match.where(since=1999)
- Parameters:
predicates – Cypher expressions to add to the WHERE clause
properties – exact property match keys and values
- Returns:
refined
RelationshipMatch
object
Applying predicates¶
Predicates other than basic equality can be applied to a match by using the built-in predicate functions.
For example, to match all nodes with a name that starts with “John”, use the STARTS_WITH
function, which corresponds to the similarly named Cypher operator:
>>> nodes.match("Person", name=STARTS_WITH("John")).all()
[Node('Person', born=1966, name='John Cusack'),
Node('Person', born=1950, name='John Patrick Stanley'),
Node('Person', born=1940, name='John Hurt'),
Node('Person', born=1960, name='John Goodman'),
Node('Person', born=1965, name='John C. Reilly')]
The ALL
and ANY
functions can combine several other functions with an AND or OR operation respectively.
The example below matches everyone born between 1964 and 1966 inclusive:
>>> nodes.match("Person", born=ALL(GE(1964), LE(1966))).all()
[Node('Person', born=1964, name='Keanu Reeves'),
Node('Person', born=1965, name='Lana Wachowski'),
Node('Person', born=1966, name='Kiefer Sutherland'),
Node('Person', born=1966, name='John Cusack'),
Node('Person', born=1966, name='Halle Berry'),
Node('Person', born=1965, name='Tom Tykwer'),
Node('Person', born=1966, name='Matthew Fox'),
Node('Person', born=1965, name='John C. Reilly')]
Changed in 2020.0: the predicate system has been overhauled to provide a more idiomatic API.
Null check predicates¶
- py2neo.IS_NULL()¶
Null value predicate.
This is equivalent to the Cypher expression
x IS NULL
.
- py2neo.IS_NOT_NULL()¶
Non-null value predicate.
This is equivalent to the Cypher expression
x IS NOT NULL
.
Equality predicates¶
- py2neo.EQ(value)¶
Equal value predicate.
This is equivalent to the Cypher expression
x = value
.
- py2neo.NE(value)¶
Unequal value predicate.
This is equivalent to the Cypher expression
x <> value
.
Ordering predicates¶
- py2neo.LT(value)¶
Lesser value predicate.
This is equivalent to the Cypher expression
x < value
.
- py2neo.LE(value)¶
Lesser or equal value predicate.
This is equivalent to the Cypher expression
x <= value
.
- py2neo.GT(value)¶
Greater value predicate.
This is equivalent to the Cypher expression
x > value
.
- py2neo.GE(value)¶
Greater or equal value predicate.
This is equivalent to the Cypher expression
x >= value
.
String predicates¶
- py2neo.STARTS_WITH(value)¶
String prefix predicate.
This is equivalent to the Cypher expression
s STARTS WITH value
.>>> nodes.match("Person", name=STARTS_WITH("Kevin")).all() [Node('Person', born=1958, name='Kevin Bacon'), Node('Person', born=1957, name='Kevin Pollak')]
- py2neo.ENDS_WITH(value)¶
String suffix predicate.
This is equivalent to the Cypher expression
s ENDS WITH value
.>>> nodes.match("Person", name=ENDS_WITH("Wachowski")).all() [Node('Person', born=1967, name='Andy Wachowski'), Node('Person', born=1965, name='Lana Wachowski')]
- py2neo.CONTAINS(value)¶
Substring predicate.
>>> nodes.match("Person", name=CONTAINS("eve")).all() [Node('Person', born=1967, name='Steve Zahn'), Node('Person', born=1964, name='Keanu Reeves')]
This is equivalent to the Cypher expression
s CONTAINS value
.
- py2neo.LIKE(regex)¶
Regular expression matching predicate. The regex can be a string or an pre-existing compiled Python
re
pattern.>>> nodes.match("Person", name=LIKE("Ke.*n")).all() [Node('Person', born=1958, name='Kevin Bacon'), Node('Person', born=1962, name='Kelly Preston')]
This is equivalent to the Cypher expression
s =~ regex
.
List predicates¶
- py2neo.IN(value)¶
List membership predicate.
>>> nodes.match("Person", born=IN([1962, 1964, 1966])).all() [Node('Person', born=1964, name='Keanu Reeves'), Node('Person', born=1962, name='Tom Cruise'), Node('Person', born=1962, name='Demi Moore'), Node('Person', born=1966, name='Kiefer Sutherland'), Node('Person', born=1962, name='Anthony Edwards'), Node('Person', born=1962, name='Kelly Preston'), Node('Person', born=1966, name='John Cusack'), Node('Person', born=1962, name="Rosie O'Donnell"), Node('Person', born=1966, name='Halle Berry'), Node('Person', born=1966, name='Matthew Fox')]
This is equivalent to the Cypher expression
x IN list
.
Connectives¶
- py2neo.AND(*values)¶
Connective wherein all predicates must evaluate true.
>>> nodes.match("Person", born=AND(GE(1964), LE(1966))).all() [Node('Person', born=1965, name='John C. Reilly'), Node('Person', born=1964, name='Keanu Reeves'), Node('Person', born=1965, name='Lana Wachowski'), Node('Person', born=1966, name='Kiefer Sutherland'), Node('Person', born=1966, name='John Cusack'), Node('Person', born=1966, name='Halle Berry'), Node('Person', born=1965, name='Tom Tykwer'), Node('Person', born=1966, name='Matthew Fox')]
This is equivalent to the Cypher expression
(pred1 AND pred2 AND ...)
.
- py2neo.OR(*values)¶
Connective wherein at least one predicate must evaluate true.
>>> nodes.match("Person", name=OR(STARTS_WITH("H"), ENDS_WITH("h"))).all() [Node('Person', born=1960, name='Hugo Weaving'), Node('Person', born=1943, name='J.T. Walsh'), Node('Person', born=1941, name='Jim Cash'), Node('Person', born=1963, name='Helen Hunt'), Node('Person', born=1950, name='Howard Deutch'), Node('Person', born=1966, name='Halle Berry'), Node('Person', born=1985, name='Emile Hirsch')]
This is equivalent to the Cypher expression
(pred1 OR pred2 OR ...)
.
- py2neo.XOR(*values)¶
Connective wherein exactly one predicate must evaluate true.
>>> nodes.match("Person", name=XOR(STARTS_WITH("H"), ENDS_WITH("h"))).all() [Node('Person', born=1960, name='Hugo Weaving'), Node('Person', born=1943, name='J.T. Walsh'), Node('Person', born=1941, name='Jim Cash'), Node('Person', born=1963, name='Helen Hunt'), Node('Person', born=1966, name='Halle Berry'), Node('Person', born=1985, name='Emile Hirsch')]
This is equivalent to the Cypher expression
(pred1 XOR pred2 XOR ...)
.
Custom predicates¶
For predicates that cannot be expressed using one of the built-in functions, raw Cypher expressions can also be inserted into NodeMatch.where()
method to refine the selection.
Here, the underscore character can be used to refer to the node being filtered:
>>> nodes.match("Person").where("_.born % 10 = 0").all()
[Node('Person', born=1950, name='Ed Harris'),
Node('Person', born=1960, name='Hugo Weaving'),
Node('Person', born=1940, name='Al Pacino'),
Node('Person', born=1970, name='Jay Mohr'),
Node('Person', born=1970, name='River Phoenix'),
Node('Person', born=1940, name='James L. Brooks'),
Node('Person', born=1960, name='Annabella Sciorra'),
Node('Person', born=1970, name='Ethan Hawke'),
Node('Person', born=1940, name='James Cromwell'),
Node('Person', born=1950, name='John Patrick Stanley'),
Node('Person', born=1970, name='Brooke Langton'),
Node('Person', born=1930, name='Gene Hackman'),
Node('Person', born=1950, name='Howard Deutch'),
Node('Person', born=1930, name='Richard Harris'),
Node('Person', born=1930, name='Clint Eastwood'),
Node('Person', born=1940, name='John Hurt'),
Node('Person', born=1960, name='John Goodman'),
Node('Person', born=1980, name='Christina Ricci'),
Node('Person', born=1960, name='Oliver Platt')]
Ordering and limiting¶
As with raw Cypher queries, ordering and limiting can also be applied:
>>> nodes.match("Person").where(name=LIKE("K.*")).order_by("_.name").limit(3).all()
[Node('Person', born=1964, name='Keanu Reeves'),
Node('Person', born=1957, name='Kelly McGillis'),
Node('Person', born=1962, name='Kelly Preston')]