Making a relation in neo4j - 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!"

Related

Is there a way to make a relation when creating a node, on a certain condition? Cypher 3.5

I am new to Neo4j and graph databases.
I am looking for a way create a node while connecting it to another node matching that has a field that matches a certain parameter.
Here's a diagram to get the idea:
Let's say my parameter is :params {friendNodeId: 2}
In my Cypher query, I would like to create my new node with its field name: "my brand new node". Then if there is a node having uniqueId = $params.friendNodeId create a relation between this node and my new node.
My approach is to optimize the entire process by running a single query and not having to make an unnecessary match in a second query to get the newly created node.
If you think that it doesn't make sense at all don't hesitate to come up with another proposition.
Thanks for your help.
From your example in the comments, if the node creation is mandatory, but the relationship creation is optional (depending on if there is a node that matches), then you can just move the CREATE to before your MATCH:
CREATE (new:Node {uId: 4})
SET new.name = "name 4"
WITH new
MATCH (other:Node {uId: $uniqueId})
CREATE (new)-[r:FRIEND]->(other)
RETURN r

Create a relationship only if not exist in neo4j

I want to add a relationship between two nodes, but only if the relationship does not exist. For example:
The Relationship between node1 and node2 currently exists with these properties: time:41221323,link:www.google.com
I am trying to add a relationship with different properties for example:
time:5344241,link:www.google.com
In this case i want to keep the original properties on the relationship.
You can use the below CQL query:
MATCH(a: startNodeLabel {attributes to match start node})
MATCH(m:endNodeLabel {attributes to match end node})
MERGE(a)-[:relationshipName]->(m)
The above merge statement creates relation between nodes a and m if there is no existing relationship between a and m.
You want either the MERGE or CREATE UNIQUE clause:
http://neo4j.com/docs/stable/query-merge.html
http://neo4j.com/docs/stable/query-create-unique.html
Also note that MERGE comes with additional ON CREATE SET and ON MATCH SET so you can control when properties get set.
I believe if you give either specific properties as part of the match syntax it will not create only if all of the properties match exactly.
Create Unique clause does serve this purpose. Neo4j Documet says
CREATE UNIQUE is in the middle of MATCH and CREATE — it will match
what it can, and create what is missing. CREATE UNIQUE will always
make the least change possible to the graph — if it can use parts of
the existing graph, it will.
START a=node(...), b=node(...)
CREATE UNIQUE (a)-[r:LIKES]-(b)
return a,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)

Redundancy of graph in Neo4j

I have created a small graph in Neo4j and the respective nodes and relationships are created. If I run the same code again, the nodes and relationships are again created instead of displaying the message like the nodes and relationships already exist similar like Oracle.
MERGE (a:Person1 { name : 'ROGER', title : 'Developer', age :28})
MERGE (b:Person2 { name : 'Britney', title : 'financier',age :32})
MERGE (c:Person3 { name : 'Christian', title : 'tester',age :24})
Create (a)-[:HUSBAND{last_name:'WHITE'}]->(b) RETURN a,b,c;
So I want to clarify whether Neo4j has duplication or the nodes will be created many times
Thanks in advance...
For reference, the MERGE statements are not creating new persons, only your CREATE statement in the end, see http://console.neo4j.org/r/qrzr6u saying upon re-execution
created 1 relationship set 1 property
You probably want the MERGE on all statements:
MERGE (a:Person1 { name : 'ROGER', title : 'Developer', age :28 })
MERGE (b:Person2 { name : 'Britney', title : 'financier', age :32 })
MERGE (c:Person3 { name : 'Christian', title : 'tester', age :24 })
MERGE (a)-[:HUSBAND { last_name:'WHITE' }]->(b)
RETURN a,b,c;
See http://console.neo4j.org/r/vmfl2v for an example.
MERGE does not re-create data if it already exists. CREATE always creates data, even if it already exists.
The documentation on merge points out that it always matches on the full pattern.
In the case of the cypher snippet you gave us, if you ran it twice you should end up with only one copy of Roger, Britney, and Christian, but I would expect two separate relationships between Roger and Britney, because CREATE always creates.
Watch out for the gotcha on MERGE though, it always merges on the full pattern you specify. So for example if you do this:
MERGE (a:Person {fname: "Henry"});
MERGE (a:Person {fname: "Henry", lname: "Banks"});
Then you get two Henrys, one with no lname property, and one with. This is because the second MERGE looks for a Person node with fname:Henry, lname:Banks and fails to find it, so it creates one. It does not add an extra property to an existing node. This is a common trip-up using MERGE.
Another common trip-up using MERGE (again due to the "whole pattern match") is this:
MERGE (a:Person {name:"Henry"})-[:knows]->(b:Person {name: "Mary"});
MERGE (a:Person {name:"Henry"})-[:married]->(b:Person {name: "Mary"});
This ends up creating two Henry's and two Mary's.

Neo4j Behaviour of Merge

So I have a use case where periodically I update my graph with complex subgraphs. In these subgraphs there will be nodes which are already in the graph, and nodes which are new. I had thought that Merge should do this, but in fact merge appears to create a new node even if there was already a unique node, if the property specifications are not identical.
E.g. on the Neo4j Console, Suppose that I do:
MERGE (a:Crew {name:'Neo', occupation:'The One'})
MERGE (a:Crew {name:'Adam', occupation:'Mechanic'})
CREATE UNIQUE (a)-[r:KNOWS]->(b)
RETURN *
That causes the console to create a second version of Neo, rather than to simple attach the occupation to the existing version.
This happens even if you use:
CREATE CONSTRAINT ON (p:Crew) ASSERT p.name IS UNIQUE
Although now it just refuses to create anything since it won't match the two neo's as one property is blank, and it isn't allowed to create a new node either.
It creates a second version because it's not unique. You're specifying an additional property, "occupation", which doesn't currently exist in the original Neo node, so it doesn't find a match and therefore creates a new node.
Use this instead:
MERGE (a:Crew {name:'Neo'}) ON CREATE SET a.occupation='The One'
MERGE (a:Crew {name:'Adam'}) ON CREATE SET b.occupation='Mechanic'
MERGE (a)-[r:KNOWS]->(b)
RETURN *
See also: http://docs.neo4j.org/refcard/2.1/

Resources