Creating relationship conditionally with cypher (neo4j) - neo4j

I am attempting to create a linked list with neo4j, and have a root node with no relationships. Here is the pseudo cypher I am trying to create, but I am not sure how, or even if it is possible:
START root=node(1), item=node(2)
MATCH root-[old?:LINK]->last
WHERE old IS NOT NULL
CREATE root-[:LINK]->item-[:LINK]->last
DELETE old
WHERE old IS NULL
CREATE root-[:LINK]->item
Basically I am trying to insert a node into the list if the list exists, and simply create the first list item otherwise. Obviously you cannot do multiple WHEREs like I have done above. Any ideas how I can achieve this desired functionality with a cypher?
The docs solve the problem by first creating a recurrent :LINK relationship on the root node, but I would like to solve this without doing that (as you then need to create possibly unnecessary relationships for each node).

For anyone interested, I figured out a way to solve the above using some WITH tricks. This is essentially a solution for creating linked lists in neo4j without having to first create a self referencing relationship.
START root=node(1), item=node(2)
MATCH root-[old?:LIST_NEXT]->last
CREATE root-[:LIST_NEXT]->item
WITH item, old, last
WHERE old IS NOT NULL
CREATE item-[:LIST_NEXT]->last
DELETE old
This works by first looking for an existing link relationship, and creating the new one from the root to the item. Then by using WITH we can chain the query to now examine whether or not the matched relationship did in fact exist. If it did, then remove it, and create the remaining link piece from the new item to the old one.

For this, you might want to look at MERGE, http://docs.neo4j.org/chunked/snapshot/query-merge.html#merge-merge-with-on-create-and-on-match
And maybe at the linked list example, http://docs.neo4j.org/chunked/snapshot/cookbook-linked-list.html

Related

Cypher: Creating a schema index that already exists

When you ask Neo4j to create an index that already exists it does not thrown an exception, which seems good for my purpose.
session.run("CREATE INDEX ON :User(email)");
Question 1:
But how is neo4j handling this under the hood? Does it delete the index then recreate it or does it ignore the query altogether since the index already exists?
I'd like to know because I have some CRUD operations and I'd like to define the schema for my nodes at the moment I create them, which means calling "CREATE INDEX" and so fourth. The drawback is this means for every new node created redundant calls to create an index are made, which is fine if they are ignored if the index already exists.
Question 2:
I noticed the following works even if no nodes exist with the label User yet (Meaning I can create labels and index before the associated nodes).
CREATE INDEX ON :User(email)
I'm new to Neo4j and use to the RDBMS world where you can't create an index on a column that does not exist. Am I correct in my belief that creating Indexes and labels before I've even created the nodes that have those labels and properties should not cause any unforeseen problems down the road?
Answering question #2, creating indexes and constraints even when no nodes with those labels or properties exist is perfectly fine, and is in fact an extremely common case. I highly recommend going this route.
I'd recommend against creating indexes with every node creation. While I don't believe it causes much in wasted cycles, it doesn't seem like good design.
Question 1
This won't work if you are creating constraints. They can only be called once and if they exist THEY will indeed throw an exception. Normal indexes don't seem to do so this whole approach should not be attempted.
Question 2
See InverseFalcons comment but it seems to be the correct approach.

Cypher: Create relationships between nodes based on a common property key id

I'm brand new to Cypher (and Stackoverflow) and am having trouble creating relationships between nodes based on share property keys.
I would like to do something like this:
MATCH (a:Person)-->()<--(b:Country)
WHERE HAS (a.id) AND HAS (b.id) AND a.id=b.id
CREATE (a)-[:LIVES]->(b);
to create a relationship between Country node and Person nodes where they share the same id.
The above creates no errors when run but doesn't create any relationships either and I know that the ids should match.
Many thanks!!
EDIT:
I think I know what is going wrong - I'm asking to match nodes that have a relationship to eachother but no relationships are set up yet hence 0 results. I have now tried:
MATCH (a:Person),
(b:Country)
WHERE HAS (a.id) AND HAS (b.id) AND a.id=b.id
CREATE (a)-[:LIVES]->(b);
and the query is running. It's a big data set so might take a while......
That worked. Had to reduce the size of my data set (down from 64k nodes) as Neo4j was taking way too long to process but once I had a smaller set it worked fine.
One minor addition for future Googlers.
per the help files as of version 3.4
The has() function has been superseded by exists() and has been removed.
The new code should read
MATCH (a:Person),
(b:Country)
WHERE EXISTS (a.id) AND EXISTS (b.id) AND a.id=b.id
CREATE (a)-[:LIVES]->(b);

CREATE UNIQUE in Neo4j not working?

I currently have a graph database that tries to model geographical data.
For the sake of simplicity, one of the relationships I'm using is (Object)-[:IS_IN]-(Object) to relate entities (for example place1 is in city1).
Right now I'm trying to add certain places to the DB, while trying to preserve any kind of already existing nodes. So if for example I already have a relationship such as (place1)-[:is_in]->(city1) and then try to add a (place2)-[is_in]->(city1) relationship, it should link place 2 back to the existing city1 node instead of creating a new one with the same name. So I tried using CREATE UNIQUE like this:
MATCH (obj:Object {name: 'place2'}) CREATE UNIQUE (obj)-[:IS_IN]->(city:Object {name: 'city1' })
However, this keeps creating new nodes named city1. What gives? Should I be using MERGE instead?
Use
MATCH (obj:Object {name: 'place2'}), (city:Object {name: 'city1' } CREATE UNIQUE (obj)-[:IS_IN]->(city)
instead.
I came across the same problem and found this solution that works fine for me :
MERGE (obj:Object {name: 'place2'}) MERGE (city:Object {name: 'city1' }) CREATE UNIQUE (obj)-[:IS_IN]->(city)
What this does (as I understand it) : Finds 'place2' node or creates it if it doesn't exist, finds 'city1' node or creates it if it doesn't exist, creates a :IS_IN relationship if it doesn't exist.
So, whatever the initial situation is, you end up with the complete pattern, but no node or relationship dupl.
I tested it with various starting situations and it worked as expected.
Note that I'm a Neo4j and cypher beginner, this may not be the best solution.
The question is old, I answered it anyway because other people may find it useful.

how to create unique relationships neo4j 2.0

I am trying to create some unique relationships between entities in neo4j. Right now I have authors and articles, with a Authored relationship between them. I want to create a CoAuthored relationship between the entities
Like so
match (a)-[r]->(b)<-[r2]-(c)
create (a)-[new:CoAuthor]->(c)
However, I would like to create a unique co-author relationship, but update the weight if it already exists. I saw this postm but the syntax is no longer supported In Cypher, how can I create a relationship if it doesn't exist; update property if it does
SyntaxException: This syntax is no longer supported (missing properties are now returned as null). Please use (not(has(<ident>.weight)) OR <ident>.weight=<value>) if you really need the old behavior.
I do not quite understand what it is that I am replacing. I looked at the Merge command, but can't quite get it to work
You should be able to replace create with merge in this particular case.
match (a)-[r]->(b)<-[r2]-(c)
merge (a)-[new:CoAuthor]->(c)
on create set new.weight=1
on match set new.weight=new.weight+1

neo4j Cypher create or updating

Using Neo 2.0 through REST API /cypher I'm trying to build a rooted tree like structure.
I currently have an indexed start node, I want to attach a unique path of nodes which may already exist. How can I get cypher to create and set or just update if its already in the database but missing certain properties.
Cypher's MERGE command does this, see http://docs.neo4j.org/chunked/milestone/query-merge.html.
I have the same issue currently. I'm looking into CREATE UNIQUE might be what you are after.
http://neo4j.com/docs/stable/query-create-unique.html
edited: actually I think CREATE UNIQUE might be deprecated.

Resources