what does colon mean in a merge clause in neo4j? - neo4j

MERGE (robert:Critic)
RETURN robert, labels(robert)
A new node is created because there are no nodes labeled Critic in the database.
But what is robert?and what does a colon mean?
MERGE (charlie { name: 'Charlie Sheen', age: 10 })
RETURN charlie
A new node with the name 'Charlie Sheen' will be created since not all properties matched the existing 'Charlie Sheen' node.
but in this example,there is no colon,why the variable charlie is still returned?

robert is a variable name that has meaning only within the query in which it is used (and is not saved in the DB). It is defined and instantiated the first time it is used in the query, and as long as there is no WITH clause afterwards, the query will always use robert to refer to the same node (or relationship, path, ...).
A WITH clause will only carry forward the variables that it specifies. So, WITH robert, foo would allow the same robert variable name and value to be used after the WITH clause. But WITH foo will cause robert to be forgotten.
A colon is used in a node to designate that the following name is a label. It is also used in a relationship to designate that the following name is a type.

In this cypher, robert is the node while Critic is the node label
MERGE (robert:Critic)
In below, you are creating a node (without a node label) and with properties name and age
MERGE (charlie { name: 'Charlie Sheen', age: 10 })
Try below. Notice the colon BEFORE the node label
MERGE (:Critic)
In short, for your examples, colon is a way for you to differentiate if you are creating a node or a node label or both.

Related

Neo4j node name significance

What is the significance of node name in Neo4j. What are the repercussions of making nodes without node name. Like the query
CREATE (:player {name: "Roger", YOB: 1985, POB: "Switzerland"})
has no node name?
The node "names" are actually variables. You can assign a node (or a relationship) to a variable to handle this node in the rest of the Cypher query. The Neo4j docs says that:
When you reference parts of a pattern or a query, you do so by naming
them. The names you give the different parts are called variables.
For example, you can create a node and return it using a variable:
CREATE (node:player {name: "Roger", YOB: 1985, POB: "Switzerland"})
RETURN node
but if you are not referencing the node in the rest of the query has no necessity to assign it to a variable, in this case your Cypher example is fine.
Also, if you don't add a variable name, that the Cypher planner will automatically assign a unique variable name to the items you didn't. So the only repercussion for not using a variable name, is that you can't make explicit references to that item (Thanks to #Tezra).

What is the difference between using/(not using) MATCH in a MERGE query in cypher?

When creating a probably existing node in neo4j, i'm getting confused about the use of MATCH. What would be the difference between these two cases?
1.-
MERGE (n:Person { user_id: 1234 ,sex:'male'})
2.- MATCH (a:Person) WHERE a.user_id = 1234 AND a.sex = 'male' MERGE (n:Person { user_id: 1234 ,sex:'male'})
Actually even after reading the documentation I can't understand the usefullness of MATCH
MERGE is "get or create". If the pattern exists, get it (bind to the variables specified). If the pattern specified does not exist, then create it.
MATCH is just "get". If the pattern exists, bind to the variables specified. If the pattern does not exist, then nothing is bound to the variables.
Here are the differences between your 2 queries.
Query #1 will create a node with the specified label and properties if and only if such a node is not found.
Query #2 is basically a waste of time. It calls MATCH to look for a node with the specified label and properties, and only if it is found does it call MERGE (which would create the node if and only if it does not already exist). So, #2 ends up never making any changes. If the node already existed, it will continue to exist (since MERGE will discover it doesn't need to do anything). If it did not exist, it will remain nonexistent (since MERGE would not even be invoked).
Needless to say, one would never want to use MATCH and MERGE in the same way as #2. Here is a more typical example of MATCH and MERGE, which ensures that the SPOUSE_OF relationship exists between 2 people who are already in the DB:
MATCH (a:Person {user_id: 1234}), (b:Person {user_id: 5678})
MERGE (a)-[:SPOUSE_OF]->(b);

Cypher 'Node Already Exists' issue with MERGE

I am preplexed on why I am getting an issue with this Cypher statment when I have a unique constraint on the address of the location node but am using a merge which should find that if it exists and only return the id for the rest of the statment. What am I missing?
Here is my statement:
MERGE(l:Location{location_name:"Starbucks", address:"36350 Van Dyke Ave", city: "Sterling Heights",state: "MI", zip_code:"48312",type:"location",room_number:"",long:-83.028889,lat:42.561152})
CREATE(m:Meetup{meet_date:1455984000,access:"Private",status:"Active",type:"project",did_happen:"",topic:"New features for StudyUup",agenda:"This is a brainstorming session to come with with new ideas for the companion website, StudyUup. Using MatchUup as the base, what should be added, removed, or modified? Bring your thinking caps and ideas!"})
WITH m,l
MATCH (g:Project{title_slug:"studyuup"}) MATCH (p:Person{username:"wkolcz"})
WITH m,l,g,p
MERGE (g)-[:CREATED {rating:0}]->(m)
MERGE (m)-[:MEETUP_AT {rating:0}]->(l)-[:HOSTED_MEETUP]->(m)
MERGE (m)<-[:ATTENDING]-(p)
RETURN id(m) as meeting_id
I am getting:
Node 416 already exists with label Location and property "address"=[36350 Van Dyke Ave]
You've encountered a common misunderstanding of MERGE. MERGE merges on everything you've specified within the single MERGE clause. So the order of operations are:
Search for a :Location node with all of the properties you've specified.
If found, return the node.
If not found, create the node.
Your problem occurs at step 3. Because a node with all of the properties you've specified does not exist, it goes to step 3 and tries to create a node with all of those properties. That's when your uniqueness constraint is violated.
The best practice is to merge on the property that you've constrained to be unique and then use SET to update the other properties. In your case:
MERGE (l:Location {address:"36350 Van Dyke Ave"})
SET l.location_name = "Starbucks",
l.city = "Sterling Heights"
...
The same logic is going to apply for the relationships you're merging later in the query. If the entire pattern doesn't exist, it's going to try to create the entire pattern. That's why you should stick to the best practice of:
MERGE (node1:Label1 {unique_property: "value"})
MERGE (node2:Label2 {unique_property: "value"})
MERGE (node1)-[:REL]-(node2)

Return node with unknown-at-query-time structure, with a "computed" property added?

I need to return nodes along with their IDs, and things like this are to be avoided:
RETURN n, ID(n) as n_ID
I would very much prefer to be able to return the ID as a "computed" property of the node, so that the client sees the node as if it had a property named id.
I've been breaking my head over this for hours now. The closest I found is this comment under an unsatisfying answer to a similar question:
MATCH (n:Person) RETURN { id: ID(n), name: n.name } as user
That method is useless because it requires manually reconstructing the node as a map literal in the RETURN clause. This is impossible if you don't know all the property names, which will be the typical scenario in my application; plus, there might be lots of properties.
Next thing I tried was operator '+'. It throws a Type Mismatch; you cannot combine a Map with a Node this way. I cannot find any documented way to convert a Node to a Map either. The docs mention KEYS(), but no VALUES(), nor a way to "zip" keys and values into a map.
Another thing I thought of trying:
REDUCE(theMap = {id: ID(n)}, k in KEYS(n) | theMap + { what? : what? })
... but I know neither how to do a "variable key" in an array literal, nor how to access a node's property by a variable key.
Is what I am trying to do at all possible in cypher?
You can add the id property right after you CREATE a node (and in the same transaction). For example:
CREATE (n:Person {name: "Fred", address: "123 Main St"})
SET n.id = ID(n)
RETURN n;
This way, your nodes will actually have an id node -- there is no need to compute it later.
Depending on what you are doing with the id, you might want to reconsider returning the Neo4j node id (the internal id) and instead generate and store a UUID property on each node. Internal node ids can be reused and should not be used to reference nodes in an external system. Internal ids represent an offset in the store file and if nodes are deleted these gaps in the store file can be filled in, reclaiming already used ids.
There is a plugin here that can automate UUID creation and a discussion on Github here.

Making a relation in neo4j

I am not sure what I am doing wrong here, so here is how I create nodes
CREATE (urlnode_1:UrlNode {url:'url1', nodenumber:1})
CREATE (urlnode_2:UrlNode {url:'url2', nodenumber:2})
I create relations as follows
CREATE
(urlnode_1)-[:OutLink {anchor_text:['MY']}]->(urlnode_2)
Two nodes are created successfully first, now on running the code to create the relation, I would have liked the relation to exist between the two created nodes but it creates two new nodes say 3 and 4 and shows a relation between them. What am i doing wrong here?
To guide you the best way I can, let's sum up some Neo4j basics concerning node and relationships creation :
A node can have one or more labels, labels are meaned to group the nodes by domain (User, Speaker, Company, etc..see a label as a table name for e.g. ). A node can also have properties.
A relationship can have only ONE type, relationships are organizing the graph. Relationships can also have properties.
To create a node, you can use the CREATE writing clause :
CREATE (n:Person {firstname: 'John'})
The CREATE statement will not check if other nodes with same label and properties already exists, it will just create a new node
Relationships can also be created with the same clause :
MATCH (n:Person {firstname: 'John'}), (p:Person {firstname: 'Pierre'})
CREATE (n)-[:KNOWS]->(p)
A complete pattern can also be created in one go :
CREATE (n:Person {name:'Chris'})-[:KNOWS]->(p:Person {name:'Oliver'})
REMINDER : CREATE will not check for existing nodes.
--- AND NOW MERGE ---
MERGE will lazily check for existing nodes, see him as a MATCH OR CREATE clause :
MERGE (n:Person {firstname:'Fred'})
If the node with label Person and firstname Fred does not exist, the node will be created, otherwise nothing will happen. This is where come the handy ON MATCH and ON CREATE mentionned by #joslinm .
If you run this query multiple times after the node creation, your graph will not change, if you know the http protocol, you can say that MERGE is an indempotent request.
Be aware that, MERGE will ensure that an entire pattern exist in the database, by creating it if it does not already exist, meaning that if you do MERGE with a complete pattern, the entire pattern will be looked up for existence, not a single node :
Say a node with label Person and name property with value 'John' already exist in the db :
MERGE (n:Person {name:'John'})
will not affect the graph
However :
MERGE (n:Person {name:'John'})-[:KNOWS]->(:Person {name:'Nathalia'})
A new John node will be created, because the entire pattern does not exist.
It is recommended to use MERGE incrementally :
MERGE (n:Person {name:'John'})
MERGE (p:Person {name:'Nathalia'})
MERGE (n)-[:KNOWS]->(p)
If you want to know more about the MERGE clause, I can highly recommend you this wonderful article from Luanne on GraphAware : http://graphaware.com/neo4j/2014/07/31/cypher-merge-explained.html
Chris
If you create a relationship, a new one will get created every single time. They are not inherently unique. It sounds like you'd rather be merging the relationship; i.e., if they relationship is there, match it, if not, create it.
The merge syntax for it is as follows:
MERGE (a:Node)-[:LIKES]->(b:Node)
ON
MATCH SET a.msg = 'I matched!'
ON
CREATE SET a.msg = 'I created!'
RETURN a
You can try it out here: http://console.neo4j.org/
You'll notice that first the msg will be "I created!" then after it matches, it will be "I matched!"

Resources