jameshfisher
jameshfisher

Reputation: 36395

Cypher: what parts of a pattern can be bound to a variable?

I can get all User nodes like this:

MATCH (n:User)
RETURN n

In this case, n is bound to the node. But let's say I want to write a Cypher query which gets the name property of every node with the label User and a property with the key name, and return this as username. I write:

MATCH (n:User { name: username })
RETURN username

But this appears to not be possible: the Cypher parser does not accept the identifier username in that location of the pattern. Is there another way to do it? What positions of a pattern is it possible to put an identifier? Just nodes and relationships?

(Yes, I'm aware I can bind to the node, check whether a name property exists, and if so extract that value. But it would be more elegant to directly pattern match on the property.)

Upvotes: 3

Views: 1136

Answers (4)

jameshfisher
jameshfisher

Reputation: 36395

No, it is not possible to bind a property value to an identifier in a pattern. The only things that can be bound to identifiers in a pattern are nodes and relationships.

The only way to achieve the same query is to manually check for the existence of the property key on the node and extract the property value if the key exists, like this:

MATCH (n:User)
WHERE HAS (n.name)
RETURN n.name AS username

Upvotes: 0

Nicole White
Nicole White

Reputation: 7790

To answer the question posed in the title:

Within the MATCH clause specifically, paths, nodes, and relationships can be bound to identifiers:

MATCH p = (n)-[r]-(m)

After the MATCH clause, in combination with the WITH clause, anything can be bound to an identifier:

MATCH p = (n)-[r]-(m)
WITH n.name AS identifier

or

MATCH p = (n)-[r]-(m)
WITH COUNT(r) AS some_identifier

or

MATCH p = (n)-[r]-(m)
WITH EXTRACT(x IN NODES(p) | x.name) AS another_identifier

etc.

Use WITH if you want to bind anything other than a path, node, or relationship to an identifier. Your specific example seems to showcase a misunderstanding of the role of the curly braces within a MATCH clause. They are there for what I like to call "shorthand WHERE conditioning." The curly braces allow you to condition on node and relationship properties within the MATCH clause instead of conditioning in a subsequent WHERE clause.

MATCH (n:User {name:"Alice"})
RETURN n

and

MATCH (n:User)
WHERE n.name = "Alice"
RETURN n

are identical. It is a matter of convenience / preference.

TL;DR - No, you can't bind the name property to an identifier username within a MATCH clause. Use WITH n.name AS username to do this.

Upvotes: 4

JohnMark13
JohnMark13

Reputation: 3739

Edit - Actual Answer
With regards to binding a variable to the matched properties this is not possible. Like you say the binding is only applicable to Nodes and Relationships. You can also name values in Return statements and in With clauses.

It is important to note that the values in parenthesis are used to select nodes (like a WHERE clause) but only work on exact matches. I'm not sure if there is any roadmap item for allowing pattern matching inside the parenthesis, making this valid:

MATCH (n:User{name:"Jam.*"})
RETURN n

In previous iterations of Neo (and you still can if you wish) you could use the START semantics to do index matches based on a Lucene Index, but that too would not have allowed property binding.

Still you do not need to test for the presence of the property as a missing property will not match anyway. As you correctly surmised your only option is:

MATCH (n:User)
WHERE n.name =~ "James.*"
RETURN n.name AS username

Or for non regex:

MATCH (n:User{name:"James"})
RETURN n.name AS username


Original Answer
Of course, if you want to match all users and return a list of values.

MATCH (n:User)
RETURN n.name AS username

Or a single value which contains an array of usernames:

MATCH (n:User)
RETURN COLLECT(n.name) AS usernames

Or if you want to match a specific user:

MATCH (n:User{propToMatch:"valToMatch"})
RETURN n.name AS username

Values in the MATCH in parenthesis are used like a WHERE clause and not as the return value.

Upvotes: 0

Michael Hunger
Michael Hunger

Reputation: 41676

You can easily return properties of a node

MATCH (n:User)
RETURN n.name

you can access these properties in any expressions

MATCH (n:User)
WHERE n.name = "John"
RETURN n.name

if you want to assign this property to an indentifier you can do it with WITH

MATCH (n:User)
WITH n.name as userName   
RETURN userName

Upvotes: 2

Related Questions