Neo4j Cypher Relationship syntax - neo4j

https://neo4j.com/docs/developer-manual/current/get-started/cypher/#cypher-intro-patterns-relationship-syntax
The Neo4j Developer Manual section 2.2.1.2 describes the syntax for Relationships. I have a question regarding the 4th example as copied below.
-[role:ACTED_IN {roles: ["Neo"]}]->
What do the square brackets surrounding ["Neo"] denote? Is this the syntax for an array? If so, how do we identify the elements of this array?
Basically, I'm trying to understand the difference between the above relationship and the one below.
-[role:ACTED_IN {roles: "Neo"}]->

It is an array, you're matching an ACTED_IN relationship which has a property called roles whose value is an array with one String element equal to "Neo"
If you want to match any element in the array you would change this to
WHERE "Neo" IN role.roles
In the second example, you're matching a property called roles whose value is simply a String equalling "Neo"

Related

When to use a Property as opposed to a Label in Neo4j?

I am going over this YouTube tutorial, "Using LOAD CSV in the Real World".
The tutorial shows how to take a CSV, where each row is a complaint made against some bank, and model it as a Neo4j dictionary.
When doing so, the narrator sets Properties on the Complaint node:
CREATE (complaint:Complaint {id: line.`Complaint ID`})
SET complaint.year= TOINT(date[2]),
complaint.month= TOINT(date[0]),
complaint.day = TOINT(date[1])
I'm confused about a small point -- what makes this date information more of a 'Property' than a Label?
Could this be modeled instead where the node has this information encapsulated as Labels instead of Properties? At what point do you need one of these and not the other?
Labels and properties are very different things.
A property belongs to a node or a relationship, and has a name and a value.
A node label is similar in concept to a "class name", and has no value.
So, it does not make any sense to talk about putting a date value in a "label". You can only put a value in a property.
Note, however, that people often use a label name (e.g., "Foo") as a shorthand for "node that has the Foo label". For example, they may say "store the date in Foo" when they actually mean "store the date in the appropriate property of a node with the label Foo". Perhaps this is what is causing the confusion.
As cybersam pointed out in his answer, labels cannot contain values. They are just... labels. Like a tag. Taking this in a slightly different direction:
A long, long time ago, in a version far, far away, Neo4j didn't have labels. So, if you wanted to identify a particular type of node (say... a Person)... you'd likely include a property+value such as nodeType = 'Person'. And then you'd include a filter in your queries, such as:
WHERE node.nodeType = 'Person'
Labels make such a property type obsolete, and are also indexable. Further, you may have multiple labels on a node (which would require your legacy nodeType property to be an array, and not as efficient to search).
So: Labels for tagging/indexing. Properties for holding values.
" Node labels serve as an anchor point for a query. By specifying a label, we are specifying a subset of one or more nodes with which to start a query. Using a label helps to reduce the amount of data that is retrieved." https://graphacademy.neo4j.com/

Basic questions about path syntax in Cypher

I have questions about the syntax of this Cypher query:
MATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(tomHanksMovies)
RETURN tom, tomHanksMovies
I swear I've seen some paths that have two dashes, as in --[:ACTED_IN]. What is the difference between two and one dash?
The relationship in the MATCH pattern is: [:ACTED_IN]. I think it's safe to say that the key is missing because there is no need for an identifier.
By extension, then why doesn't (tomHanksMovies) need to be written to explicitly show that it is basically just an identifier, as in (tomHanksMovies:)? Or is it not an identifier? I've read it called a variable as well. What's the correct terminology?
You would have seen Cypher patterns like this: (a)-->(b), but never (a)--[:ACTED_IN]->(b), as the latter is not legal. The -- syntax just means that there is a relationship, but the relationship type does not matter (and you don't need to use any relationship properties).
You indicate an identifier as the first string after the ( for a node or [ for a relationship, as long as the string does not start with a : or { character. The : character is used before a node label or relationship type. The { and } characters are used enclose property name/value pairs.
An identifier is referred to that way in the neo4j documentation, so that is the preferred name. However, people often use variable as well.

How to match nodes only by value? (not defining specific property)

I want to search nodes by value only, which can be in any of node properties. I know that this is an expensive operation, but nodes will be cut off by some relationship conditions.
I want something like this:
MATCH (n: {*:"Search value"})
RETURN n
Where * imply "any property".
Is there a way to do this?
interesting tidbits can be found in this abstract regarding this topic and why it might not be implemented
https://docs.google.com/document/d/1FPfGkgzhcRXVkleBLBsA92U94Mx4yafu3nO-Xf-NzsE/edit#heading=h.pyvdg2rbofq
Semantics of dynamic key expressions
Using a dynamic key expression like <mapExpr>[<keyExpr>] requires that <mapExpr> evaluates to a map or an entity, and that <keyExpr> evaluates to a string. If this is not the case, a type error is produced either at compile time or at runtime.
If this is given, evaluating <mapExpr>[<keyExpr>] first evaluates keyExpr to a string value (the key), and then evaluates <mapExpr> to a map-like value (the map). Finally the result of <mapExpr>[<keyExpr>] is computed by performing a lookup of the key in the map. If the key is found, the associated value becomes the result. If the key is not found, <mapExpr>[<keyExpr>] evaluates to NULL.
Thus the result of evaluating <mapExpr>[<keyExpr>] can be any value (including NULL
Caveats
Dynamic property lookup might entice users to encode information in property key names. This is bad practice as it interferes with planning, leads to unnatural data models, and might lead to exhausting the available property key id space. This is addressed by issuing a warning when a query uses a dynamic property lookup with a dynamic property key name.
To my knowledge, no. Seems to me that what you really are trying to do would be better achieved by creating a search index over the graph using something like elasticsearch or solr. This would give you the ability to search over all properties. Your choice of analyzer whilst indexing would give you the option of exact or partial value matches.

Combining two neo4j cypher calls into one call

I have the following two cypher calls that I'd like to combine into one;
start r=relationship:link("key:\"foo\" and value:\"bar\"") return r.guid
This returns a relationship that contains a guid that I need based on a key value pair (in this case key:foo and value:bar).
Lets assume r.guid above returns 12345.
I then need all the property relationships for the object in question based on the returned guid and a property type key;
start r=relationship:properties("to:\"12345\" and key:\"baz\"") return r
This returns several relationships which have the values I need, in this case all property types baz that belong to guid 12345.
How do I combine these two calls into one? I'm sure its simple but I'm stumbling..
The answer I've gotten is that there is no way to perform an index lookup in the middle of a Cypher query, or to use a variable you have declared to perform the lookup.
Perhaps in later version of Cypher, as this ability should be standard especially with the dense node issue and the suggested solution of indexing.

neo4j not reusing existing vertex in cypher create unique query

A portion of my neo4j graph represents objects, their values, and the attributes associated with those values. To use common programming syntax, I'm persisting something like the result of:
Object.Attribute = Value
where Object, Attribute and Value are all nodes, and they're linked by VALUE and ATTRIBUTE relationships like this:
Object-[:VALUE]->Value-[:ATTRIBUTE]->Attribute
To describe this with a specific example, the result of this code:
Object.Colour = 'Red'
would be persisted as:
Object-[:VALUE]->(Value { value:'Red' })-[:ATTRIBUTE]->(Attribute { name:'Colour' })
The problem occurs when I want to modify a persisted state like that above, and I wish to re-use existing Attribute (and ideally, Value) nodes - that is, I don't want to have multiple instances of the Attribute { name:'Colour' } node, I want to have a single instance that is related to each Value node instance.
The following Cypher query will go ahead and create new Value and Attribute nodes every time, regardless of whether identical nodes already exist:
start o=node(something)
create unique o-[:VALUE]->(v {value:'Green'})-[:ATTRIBUTE]->(a {name:'Colour'})
return v;
The following will apparently recycle both Value and Attribute nodes, but of course won't work when the required Attribute doesn't exist (i.e. the first time it's used):
start o=node(something), a=node(something)
create unique o-[:VALUE]->(v {value:'Green'})-[:ATTRIBUTE]->a
where a.name = 'Colour'
return v;
The statement in the documentation that "create unique will always make the least change possible to the graph — if it can use parts of the existing graph, it will", doesn't appear to be completely true, and I don't understand why my query doesn't exhibit this behaviour.
How can I get the "recycling" effect of the latter query, combined with the creation on demand of the Attribute (and Value) when required like the former?
The first problem is that you are building a property graph in a property graph. It's possible, but awkward and not always a good choice.
Your example:
http://console.neo4j.org/r/evl77k
If understood you correctly, you want to be able to change the value node and re-use the same attribute node, right?
The problem is that in your second query, you ask Cypher to find value node with a different property than what is already in your graph. Cypher can't find such a node, and so creates one for you. It then tries to find an outgoing ATTRIBUTE relationship from the newly created node, and of course it doesn't find any. So it creates a new relationship and attribute for you.
If you want to keep using the same attribute node, you simply omit the property value from the value node, like so:
START o=node(0)
CREATE UNIQUE o-[:VALUE]->(v)-[:ATTRIBUTE]->(a {name:'Colour'})
SET v.value = 'Green'
RETURN v
This will find you Colour attribute node, and then set the property for you, instead of creating new paths every time.
Makes sense?
Andrés

Resources