How to MATCH and CREATE a node and relationship? - neo4j

Learning Neo4j and need help with getting the basics right. I am trying to find a Matching candidate then create a company and create a relationship between candidate and the newly created company. So, my query is
MATCH (b:Candidate {name:'Bala'}), CREATE (e:Employer {name:'Yahoo'}),
CREATE (b)-[:WORKED_IN]->(e)
RETURN b,e;
Invalid input '(': expected whitespace, comment, '=', node labels, MapLiteral, a parameter, a relationship pattern, ',', USING, WHERE, LOAD CSV, START, MATCH, UNWIND, MERGE, CREATE, SET, DELETE, REMOVE, FOREACH, WITH, RETURN, UNION, ';' or end of input...
I am using 2.2.5 console.

Remove the two commas before CREATE. The clauses in Cypher are not comma separated, only elements within a clause are. Your query will read
MATCH (b:Candidate {name:'Bala'})
CREATE (e:Employer {name:'Yahoo'})
CREATE (b)-[:WORKED_IN]->(e)
RETURN b,e;

Related

Cypher COLLECT clause to build a list where some lists could be empty

I have a database in which I have Entity nodes, User nodes, and a couple of relationships including LIKES, POSTED_BY. I'm trying to write a query to achieve this objective:
Find all Entity nodes that a particular user LIKES or those that have been POSTED_BY that User
Note that I have simplified my query - in real I have a bunch of other conditions similar to the above.
I'm trying to use a COLLECT clause to aggregate the list of all Entity nodes, and build on that line by line.
MATCH (e)<-[:LIKES]-(me:User{id: 'rJVbpcqzf'} )
WITH me, COLLECT(e) AS all_entities
MATCH (e)-[:POSTED_BY]->(me)
WITH me, all_entities + COLLECT(e) AS all_entities
UNWIND all_entities AS e
WITH DISTINCT e
RETURN e;
This seems to be returning the correct list ONLY if there is at least one Entity that the user has liked (i.e., if the first COLLECT returns a non-empty list). However, if there is no Entity that I have liked, the entire query returns empty.
Any suggestions on what I'm missing here?
Use OPTIONAL MATCH:
MATCH (me:User {id: 'rJVbpcqzf'})
OPTIONAL MATCH (me)-[:LIKES|POSTED_BY]->(e)
RETURN collect(DISTINCT e) AS all_entities
Notes:
Instead of collecting and unwinding, you can simply use DISTINCT. You can also use DISTINCT with collect.
You can also use multiple relationship types, i.e. the LIKES|POSTED_BY for the relationship type here.

Sub queries in Cypher Query Language

I want to write a CREATE relationship statement for a project i'm working on. The statement has to be something like this
CREATE (match (p:Halt) where p.name="Ananda College" return p)-[:next_halt {route:['103'],dist:1.45}]->(MATCH (p:Halt) where p.name="Borella" return p)
As you can see i want the start node and end node to have values coming from another CQL statement.
But when i run this query there seems to be a syntax error. I have gone through some tutorials to see where my query is wrong but being a beginner i can't really tell.
Invalid input '(': expected whitespace, comment, node labels, MapLiteral, a parameter, ')' or a relationship pattern (line 1, column 15 (offset: 14))
"CREATE (match (p:Halt) where p.name="Ananda College" return p)-[:next_halt {route:['103'],dist:1.45}]->(MATCH (p:Halt) where p.name="Borella" return p)"
Your syntax is rather mixed up here. Please reread the dev documentation and maybe look at the Cypher cheat sheet.
As for proper syntax, you don't even need nesting to get what you want. First, you match on your start and end nodes, then you can use the bound variables in other parts of your query, such as to create a relationship:
MATCH (start:Halt), (stop:Halt)
WHERE start.name = "Ananda College" AND stop.name="Borella"
CREATE (start)-[:next_halt {route:['103'], dist:1.45}]->(stop)
If you aren't sure if nodes (or the relationship) exist or not, you can use MERGE instead, which will MATCH on existing nodes (or relationships) or create them if they do not exist.

Neo4j: MERGE with comma in pattern throws 'Invalid syntax', unlike MATCH or CREATE

Good morning,
To achieve idempotence I use Neo4j's MERGE keyword to insert patterns into my database. For example, I might insert a user and his friends like this:
MERGE (friend:User)<-[:FRIEND]-(me:User)-[:FRIEND]->(anotherfriend:User);
I thought I could rewrite the same statement like this:
MERGE (me:User)-[:FRIEND]->(friend:User), (me)-[:FRIEND]->(anotherfriend:User);
But this results in this error:
Invalid input ',': expected whitespace, a relationship pattern, ON, LOAD CSV, START, MATCH, UNWIND, MERGE, CREATE, SET, DELETE, REMOVE, FOREACH, WITH, RETURN, UNION, ';' or end of input (line 1, column 41)
"MERGE (me:User)-[:FRIEND]->(friend:User), (me)-[:FRIEND]->(anotherfriend:User);"
MATCH and CREATE do support this syntax. Is there any reason why MERGE doesn't? Is it simply something that hasn't been implemented yet?
Note: this is not an actual query I'm using in my application but just something simple to illustrate my point.
Thanks,
Jan
I consider this being a imperfection of the cypher implementation. Please file a github issue at https://github.com/neo4j/neo4j/issues for this.

Remove multiple redundant nodes in Neo4j

I had an XML file which I wanted to visualize in Neo4j (as a graph with interconnected nodes). The XML file had the following hierarchy:
<Organism>
<Enzyme>
<Motif>
I was successful in creating the entire graph. When I finished I realized that a lot of times different organisms had a common enzyme or 2 different enzymes had common motifs. Now there is a lot of redundancy in my graph with similar enzymes or motifs occuring multiple times. Is there an easier way to remove all except 1 of the node (either an enzyme or motif) and then connect it to different nodes? Or will i have to start from scratch?
My CREATE statements looked like this:
CREATE (jejunistrain81176:Organism { name: "Campylobacter jejuni strain 81-176" })
CREATE (jejunistrain81176_e1:Enzyme { name: "CjeFIII" })
CREATE (jejunistrain81176_m1:Motif { name: "GCAAGG" })
CREATE UNIQUE (jejunistrain81176)-[:HAS_ENZYME]->(jejunistrain81176_e1)
CREATE UNIQUE (jejunistrain81176_e1)-[:HAS_MOTIF]->(jejunistrain81176_m1)
I tried replacing all the CREATE with MERGE but it gives me the following error :
Invalid input '(': expected whitespace, comment, '=', node labels, MapLiteral, a parameter, a relationship pattern, ON, LOAD CSV, START, MATCH, UNWIND, MERGE, CREATE, SET, DELETE, REMOVE, FOREACH, WITH, RETURN, UNION, ';' or end of input (line 21, column 14)
Replacing create and create unique with merge should actually work.
You'd have to create an index or constraint for your :Label(name) pairs.
I think you're faster reimporting the data, if you want to delete and reconnect nodes you need to know which relationships you're looking at.
Something like:
MATCH (e:Enzyme)
WITH e.name as name, count(*) as cnt, collect(e) as enzymes
where cnt > 1
WITH enzymes[0] as first, enzymes[1..] as remove
UNWIND remove as enzyme
MATCH (enzyme)<-[rel:HAS_ENZYME]-(organism)
MERGE (first)<-[newRel:HAS_ENZYME]-(organism) ON CREATE SET newRel = rel
DELETE rel
WITH distinct first, enzyme
MATCH (enzyme)-[rel:HAS_MOTIV]->(motiv)
MERGE (first)-[newRel:HAS_MOTIV]->(motiv) ON CREATE SET newRel = rel
DELETE rel
DELETE enzyme;

How do I rename relationships in 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

Resources