How do I rename relationships in Neo4j? - neo4j

I realized only after importing a ton of nodes that I had created relationships called START, which is a reserved keyword. Querying the DB through the Cypher console hence always complains about the reserved keywords:
SyntaxException: reserved keyword "start n=node(0) match n<-[:START]-r
return count(r)"
The only workaround that comes to mind is creating new copy relationships with a different name and then deleting the old ones.
Is there an easy way to rename all of these relationships or some way to escape reserved keywords in Cypher?

To do the equivalent of a rename, you can create a new one and delete the old one like so:
match (n1)-[old:`Start`]->(n2)
create (n1)-[new:StartDate]->(n2)
delete old
n.b. use backticks like those around `Start` to escape reserved keywords

You are right. You cannot rename an already existing relationship. You'd have to run through all relationships, create the new one in parallel (including all properties) and then remove the old one.
You may also want to consider quoting the reserved word START in your cypher queries with backticks and leave the relationships as they are:
start n=node(0) match n<-[:`START`]-r return count(r)

match (n1)-[old:`Start`]->(n2)
create (n1)-[new:StartDate {propName:old.propName, ...}]->(n2)
delete old

You can use apoc plugin to rename labels and relationships.
You can also use this to select a subset of relationships to rename. For eg below query will rename only relationship between Jim and Alistair.
MATCH (:Engineer {name: "Jim"})-[rel]->(:Engineer {name: "Alistair"})
WITH collect(rel) AS rels
CALL apoc.refactor.rename.type("COLLEAGUES", "FROLLEAGUES", rels)
YIELD committedOperations
RETURN committedOperations

Related

query to copy a node with relations in neo4j without the clone procedure

I want to copy a node with all its properties and relations with others nodes. Im using Neo4j version 3.4.7 so I can't use the clone procedure. My node might have different types of relations and I want to copy them all. I wanted to use this query
match (map:student {name:'test'})
create (copy:student) set copy=map with copy,map
match (map)-[r1]->(n)
with collect(r1) as rels,map,copy,n
foreach( rel in rels | create (copy)-[r2:type(rel)]->(n) set r2+=rel)
return copy,n
but I get invalid syntax error using type(rel) in foreach. Is there a way to do this without knowing the types of relations?
The easiest way is to install the APOC library, and call the procedure apoc.refactor.cloneNodesWithRelationships, as documented here.
In your case, your query would become:
MATCH (map:student {name:'test'})
CALL apoc.refactor.cloneNodesWithRelationships([map])
Note: node labels usually start with an upper letter (Student is more common than student in Neo4j datasets).

How to match line of csv which is ignored by constraint and create only relationship

I have been created a graph having a constraint on primary id. In my csv a primary id is duplicate but the other proprieties are different. Based on the other properties I want to create relationships.
I tried multiple times to change the code but it does not do what I need.
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM 'file:///Trial.csv' AS line FIELDTERMINATOR '\t'
MATCH (n:Trial {id: line.primary_id})
with line.cui= cui
MATCH (m:Intervention)
where m.id = cui
MERGE (n)-[:HAS_INTERVENTION]->(m);
I already have the nodes Intervention in the graph as well as the trials. So what I am trying to do is to match a trial with the id from intervention and create only the relationship. Instead is creating me also the nodes.
This is a sample of my data, so the same primary id, having different cuis and I am trying to match on cui:
You can refer the following query which finds Trial and Intervention nodes by primary_id and cui respectively and creates the relationship between them.
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM 'file:///Trial.csv' AS line FIELDTERMINATOR '\t'
MATCH (n:Trial {id: line.primary_id}), (m:Intervention {id: line.cui})
MERGE (n)-[:HAS_INTERVENTION]->(m);
The behavior you observed is caused by 2 aspects of the Cypher language:
The WITH clause drops all existing variables except for the ones explicitly specified in the clause. Therefore, since your WITH clause does not specify the n node, n becomes an unbound variable after the clause.
The MERGE clause will create its entire pattern if any part of the pattern does not already exist. Since n is not bound to anything, the MERGE clause would go ahead and create the entire pattern (including the 2 nodes).
So, you could have fixed the issue by simply specifying the n variable in the WITH clause, as in:
WITH n, line.cui= cui
But #Raj's query is even better, avoiding the need for WITH entirely.

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;

neo4j merge 2 or multiple duplicate nodes

I am feeding my neo4j db manually using cypher, so prone to error like creating duplicate nodes:
The duplicate nodes will have each relationships to other nodes.
Is there a built-in function to merge these nodes? Or should I do it manually?
Sounds possible, but complicated with cypher script:
Get the relationships of each duplicate node
Recreate them (with their properties) with the correct node (given node id)
Remove relationships to the duplicate nodes
and finally remove the duplicate nodes.
To avoid this situation in the future, please look at the MERGE keyword in Cypher.
Unfortunately, as far as I know, there is nothing in Cypher (yet) like:
MATCH (n:MyNode),(m:MyNode)
WHERE ID(n) <> ID(m) AND
PROPS(n) IN PROPS(m) AND PROPS(m) IN PROPS(n)
(...) DELETE (...)
The fictional function PROPS of the third line is not part of Cypher language and User-Defined functions have not made it yet into Neo4j.
If you're not working with production instances, the easiest is probably to back up your data folder and try to start the insertion over (with MERGE).
Otherwise, you can also try writing a traversal to collect the duplicates and delete them in batch (here is an example with the REST API).
Try this:
MATCH (n:MyNode),(m:MyNode),(o:OtherNode {id:123})
WHERE n <> m
MATCH (m)-[r:FOO]->()
CREATE (n)-[r2:FOO]->(o)
SET r2 = r
DELETE r,m
I think you can try:
apoc.refactor.mergeNodes(nodes, options)
For relations:
apoc.refactor.mergeRelationships(rels, options)
Or:
apoc.periodic.iterate(query, options)

Adding relationship to existing nodes with Cypher

I'm trying out Neo4j for the first time. I'm using the 2.0-RC1 community edition.
I've created some nodes:
MERGE (u:User{username:'admin',password:'admin'})
MERGE (r1:Role{name:'ROLE_ADMIN'})
MERGE (r2:Role{name:'ROLE_WEB_USER'})
MERGE (r3:Role{name:'ROLE_REST_USER'})
and now I want to add relationships between the nodes. However, I don't want to clear out the existing database created with the script above, add the statements and run it again. I want to add relationships to the existing nodes. Google helped me find this:
START n=node(*), m=node(*)
where has(n.username) and has(m.name) and n.username = 'admin'
and m.name = 'ROLE_WEB_USER'
create (n)-[:HAS_ROLE]->(m)
Which works fine (even though I don't understand all the syntax). However, I am aware that this finds any node with a username property and any node with a name property, instead of using labels to check that it has the right type of node.
How can I do the same using labels?
In Neo4j 2.0 you can create schema indexes for your labels and the properties you use for lookup:
CREATE INDEX ON :User(username)
CREATE INDEX ON :Role(name)
To create relationships you might use:
MATCH (u:User {username:'admin'}), (r:Role {name:'ROLE_WEB_USER'})
CREATE (u)-[:HAS_ROLE]->(r)
The MATCH will use an index if possible. If there is no index, it will lookup up all nodes carrying the label and see if the property matches.
N.B. the syntax above will only work with Neo4j 2.0.0-RC1 and above.
Update as of 4/2020:
The new Cypher syntax is as follows. as 'CREATE INDEX ON' has been deprecated is..
CREATE INDEX FOR (n:Label) ON (n.property)

Resources