I'd like to bundle a whole bunch of operations in as few requests as possible. The logic behind is should be the following:
check if head with key=value exists, create if it doesn't
check if tail with key=value exists, create if it doesn't
create a unique relationship (all kinds of properties)
set a bunch of properties for head & tail
I already stumbled upon create unique, but this seems to work for relationships only. How do I make sure that at least the head node exist so I can run a create unique statement on it?
What I'm doing now is firing multiple requests.The first one to find out if the node exists:
start x=node:index({key}={value}) return ID(x) as id
If that doesn't return an id, I fire another request to create the node and finally the final request to create the second node and relationships:
start n=node({id})
create unique n-[:POINTS_TO {label:{label}}]->(x {{key}:{value}})
return n,x
I'm wondering if there's a nicer way to bundle of all this...
if you use the auto-index, you can do:
start n=node:node_auto_index(key={value})
with count(*) as exists
where exists=0
create (n {key: {value}}
return n;
statement 2:
start n=node:node_auto_index(key={value})
create unique n-[:REL {foo:"bar"}]->(m {a:"b"})
set r.answer = 42
set m.c="d"
return r,m;
in Neo4j 2.0 there is MERGE for what you want.
Related
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;
In Neo4j, I am trying to load a CSV file whilst creating a relationship between nodes based on the condition that a certain property is matched.
My Cypher code is:
LOAD CSV WITH HEADERS FROM "file:C:/Users/George.Kyle/Simple/Simple scream v3.csv" AS
csvLine
MATCH (g:simplepages { page: csvLine.page}),(y:simplepages {pagekeyword: csvLine.keyword} )
MATCH (n:sensitiveskin)
WHERE g.keyword = n.keyword
CREATE (f)-[:_]->(n)
You can see I am trying to create a relationship between 'simplepages' and 'sensitiveskin' based on their keyword properties being the same.
The query is executing but relationships won't form.
What I hope for is that when I execute a query such as
MATCH (n:sensitiveskin) RETURN n LIMIT 25
You will see all nodes (both sensitive skin and simple pages) with auto-complete switched on.
CREATE (f)-[:_]->(n) is using an f variable that was not previously defined, so it is creating a new node (with no label or properties) instead, and then creating a relationship from that new node. I think you meant to use either g or y instead of f. (Probably y, since you don't otherwise use it?)
I wanted to add relationships to existing nodes, so I made cypher like this:
start n1=node:node_auto_index(id='0'),n2=node:node_auto_index(id='1') create n1-[:{quantity:1}]->n2;
start n1=node:node_auto_index(id='1'),n2=node:node_auto_index(id='2') create n1-[:USES_COMPONENT{quantity:7}]->n2;
start n1=node:node_auto_index(id='1'),n2=node:node_auto_index(id='3') create n1-[:USES_COMPONENT{quantity:11}]->n2;
start n1=node:node_auto_index(id='1'),n2=node:node_auto_index(id='4') create n1-[:USES_COMPONENT{quantity:14}]->n2;
but got many error messages (error around> {quantity). When I add only one of those, it says [[ Index node_auto_index does not exist ]].
You can't create a relationship without a type. If you add a type to the first statement, e.g. USES_COMPONENT like the others, that should resolve the error. You can match a relationship without using its type, but you can't create it without a type. If you want to match it without type, then you also need to drop the :, i.e.
n1-[{quantity:1}]->n2
is a valid pattern.
With regards to index, how have you configured your node_auto_index?
The error message means you don't have an index by that name. Usually you could fix this by enabling node auto-indexing -- Which is OK, but there's a better way to write your query:
MATCH (n0), (n1), (n2), (n3), (n4)
WHERE id(n0)=0 AND id(n1)=1 AND id(n2)=2 AND id(n3)=3 AND id(n4)=4
CREATE (n0)-[:USES_COMPONENT { quantity: 1 }]->(n1),
(n1)-[:USES_COMPONENT { quantity: 7 }]->(n2),
(n1)-[:USES_COMPONENT { quantity: 11}]->(n3),
(n1)-[:USES_COMPONENT { quantity: 14}]->(n4)
RETURN n0, n1, n2, n3, n4;
It's easier to use MATCH along with a WHERE clause to find a particular node (in general). Also notice that you can create as many new relationships as you want with a single query.
Double check this query before you use it -- you were re-using the n2 variable in confusing ways, so you need to make sure I got the right IDs bound to the right nodes for you.
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/
For the following Cypher statement:
start n=node:types(id={typeId}), g=node:groups(id={groupId})
create unique (n)<-[:has_type]-(unit {props})-[:has_group]->(g)
return unit
There are cases when g may be null (i.e. a group with id groupId does not exist).
In such a case, what should I do to make this statement still create the unit, but skip the has_group relation to g?
Right now, unit does not get created, presumably because g is null.
I'm using Neo4j Advanced 1.8
Thanks!
I would suggest to move the definition of g to the where clause, since starting at a non-existing node gives error and thus one can't continue the query to the create phase. Note the '?' which handles the null values in Cypher:
start n=node:types(id={typeId})
create unique (n)<-[:has_type]-(unit {props})-[:has_group]->(g)
where g.id?={groupId}
return unit
the query might need some tweaking, this is just my first untested shot.
edit: After some trying I came to a conclusion, that you might want to do 2 different queries, first for creating the first part of relationships with the unique node which is always and the second to create the relationship to the group which may not happen:
start n=node:types(id={typeId})
create unique (n)<-[:has_type]-(unit {props})
return unit
start unit=node:unitProps({unitPropsValue}) ,g=node:groups(id={groupId})
create unique unit-[:has_group]->g
return g
the second query will fail with an error in case the group does not exist, but that does not matter since you will still reach the target. For some strange reason I couldn't manage to implement some restrictions in the where clause like I tried in the first shot. following query seems to simply jump over the where conditions (maybe a bug?) although in my comprehension of Cypher it shall match the already existing group, but it does create a new g node instead:
start n=node(1)
create unique n-[:TYPE1]-(uniq {uid:333})
with uniq
create unique uniq-[:TYPE2]->g
where has(g.gid) and g.gid=999
return g
You can use WITH clause to achieve this in one query,
start n=node:types(id={typeId})
create unique (n)<-[:has_type]-(unit {props})
WITH unit
START g=node:groups(id={groupId})
create unique (unit)-[:has_group]->(g)
WHERE g <> null
return unit
if g is null, second won't get executed at all. even WHERE g <> null might not be required here. Kindly try and confirm
You can try this
MATCH (g:groups)
WHERE id(g)={groupId}
create unique (unit {props})-[:has_group]->(g)
WITH unit, create unique (unit)-[:has_type]->(n)
return unit
Since this is the only thing I can find related to this, I will add how I am dealing with this since none of the other answers are good enough for my purposes.
MATCH (a:TEST{id:1})
OPTIONAL MATCH (b:TEST)
WHERE b.id IN [2,3,5]
// collect b so that there are no nulls, and rows aren't lost when no match
WITH a, collect(b) AS c
FOREACH(n IN c | CREATE UNIQUE (a)-[:HAS]->(n))
RETURN a
Will work for Cypher 2.3+ (I can't test any earlier than that)
For those with APOC, you can also use CALL apoc.cypher.doIt() to break out the write.