How to merge tree in neo4j - neo4j

Let's say I have a database with named nodes and that the database is either empty or has the following content:
I now need a neo4j statement, that inserts exactly that tree structure, if it does not exists already in the database.
For simple node pair merge, I could use something like
MERGE ({name: 'A'})-[:R1]->({name: 'B'})
But I want the tree structure. How do I add C here?

Firstly, you have to add a label on your tree node (Tree in my above example) and create a unique constraint on the name attribute like this :
CREATE CONSTRAINT ON (n:Tree) ASSERT n.name IS UNIQUE;
Then you can use this script to create the C node and the others is they don't exist :
MERGE (a:Tree {name: 'A'})
MERGE (b:Tree {name: 'B'})
MERGE (c:Tree {name: 'C'})
MERGE (a)-[:R1]->(b)
MERGE (a)-[:R2]->(c);
As you can see you have to use one MERGE per node, and then one MERGE per relationship.

Related

How to prevent neo4j MERGE from creating duplicate relationships?

I am attempting to create nodes and relationships if they do not exist. I do not know ahead of time if anything in the DB exists.
This is my initial query:
MERGE (t:type { name: 'aaa'})
MERGE (m:model { name: 'bbb'})
MERGE (r:region {name: 'ccc'})
MERGE (p:param {name: 'ddd'})
MERGE (i:init {value: 123})
MERGE (u:forecast {url: 'http://something.png'})
MERGE (t)-[:HAS]-(m)-[:HAS]-(r)-[:HAS]-(p)-[:HAS]-(i)-[:HAS]-(u)
This correctly produces a graph like this:
Then I run this query again, but this time I change the name of the "model" object to "bbc" (instead of "bbb"):
MERGE (t:type { name: 'aaa'})
MERGE (m:model { name: 'bbc'})
MERGE (r:region {name: 'ccc'})
MERGE (p:param {name: 'ddd'})
MERGE (i:init {value: 123})
MERGE (u:forecast {url: 'http://something.png'})
MERGE (t)-[:HAS]-(m)-[:HAS]-(r)-[:HAS]-(p)-[:HAS]-(i)-[:HAS]-(u)
Now, however, my graph looks like this:
Everything looks correct except for the three duplicated relationships.
I realize that MATCH will create the whole path if it does not exist. There must be some way to avoid creating duplicate relationships, though.
I would appreciate being pointed in the right direction!
The MERGE statement checks if the pattern as a whole already exists or not. So, if there is one node different, the whole pattern is determined as non-existent and all relationships are created.
The solution is to split this MERGE statement into multiple, i.e. one MERGE for each relationship:
MERGE (t)-[:HAS]-(m)-[:HAS]-(r)-[:HAS]-(p)-[:HAS]-(i)-[:HAS]-(u)
becomes
MERGE (t)-[:HAS]-(m)
MERGE (m)-[:HAS]-(r)
MERGE (r)-[:HAS]-(p)
MERGE (p)-[:HAS]-(i)
MERGE (i)-[:HAS]-(u)

Neo4j create graph that some nodes have more than one relationships

Over my Neo4j I want to create this graph:
SO I tried to create some nodes and relationships with:
MERGE (D:POINT {NAME:'d'})<-[:LINKS]-(A:POINT {NAME:'a'})-[:LINKS]->(B:POINT {NAME:'b'})-[:LINKS]->(C:POINT {NAME:'c'})
But I cannot find out how I will create the relationships between D and B points also I cannot find out how I will link the A and C as well.
Do you have any Idea how to do that?
In order to avoid unintentionally creating duplicate nodes and/or relationships, you must invoke MERGE on individual nodes and relationships.
To quote the dev manual:
When using MERGE on full patterns, the behavior is that either the
whole pattern matches, or the whole pattern is created. MERGE will not
partially use existing patterns — it’s all or nothing. If partial
matches are needed, this can be accomplished by splitting a pattern up
into multiple MERGE clauses.
For example, to properly create your graph without any duplicate nodes or relationships:
MERGE (A:POINT {NAME:'a'})
MERGE (B:POINT {NAME:'b'})
MERGE (C:POINT {NAME:'c'})
MERGE (D:POINT {NAME:'d'})
MERGE (A)-[:LINKS]->(B)
MERGE (A)-[:LINKS]->(C)
MERGE (A)-[:LINKS]->(D)
MERGE (B)-[:LINKS]->(C)
MERGE (D)-[:LINKS]->(B)
CREATE seems to be the natural way to me for creating nodes and relationships.
CREATE (D:POINT {NAME:'d'})<-[:LINKS]-(A:POINT {NAME:'a'})
, (A)-[:LINKS]->(B:POINT {NAME:'b'})<-[:LINKS]-(D)
, (B)-[:LINKS]->(C:POINT {NAME:'c'})<-[:LINKS]-(A)
You can do it by doing a MATCH before a MERGE eg. FOR the relationship between A and D do:
MATCH (A:POINT {NAME:'a'}),(B:POINT {NAME:'d'}) MERGE (A)-[:LINKS]->(B)

Multiple relations like join tables (neo4j)

How do I express the following in neo4j?
match or create user bob; bob works at studio; while at studio, he's allowed to doodle; while at studio, he's also allowed to type.
Here's what I have:
MERGE (u:user {name:'bob'})
MERGE (c:company {name: 'studio'})
MERGE (u)-[:works_at]->(c)-[:allowed_to]->(p:permission {name:'doodle'})
MERGE (u)-[:works_at]->(c)-[:allowed_to]->(p:permission {name:'type'})
This doesn't work as permission becomes a relation of company.
Also, is it possible to chain relations such that:
MERGE work=(u)-[:works_at]->(c)
CREATE (work)-[:allowed_to]->(p:permission {name:'doodle'})
CREATE (work)-[:allowed_to]->(p:permission {name:'type'})
where you assign a relation to a variable to continue it later on in another query?
How about modelling it so the company grants the permission? Something like this...
MERGE (u:user {name:'bob'})
MERGE (c:company {name: 'studio'})
MERGE (u)-[:works_at]->(c)
MERGE (u)-[:allowed_to]->(p1:permission {name:'doodle'})<-[:GRANTS]-(c)
MERGE (u)-[:allowed_to]->(p2:permission {name:'type'})<-[:GRANTS]-(c)
RETURN *
You can't really refer to objects via identifiers/variables you have created previously in other queries. You would have to re-match or merge those previously created objects in your new query.
Part 2 could be modelled something like this..
MERGE (u:user {name:'bob'})
MERGE (c:company {name: 'studio'})
MERGE (u)-[:DOES]->(work:Work {start_date: timestamp()} )-[:AT]->(c)
CREATE (work)-[:allowed_to]->(p:permission {name:'doodle'})
CREATE (work)-[:allowed_to]->(p:permission {name:'type'})
As an alternate, if you never need to lookup all users with a certain permission at a company, you could maintain a collection of permissions as relationship properties.
MERGE (u:user {name:'bob'})
MERGE (c:company {name: 'studio'})
MERGE (u)-[r:works_at]->(c)
SET r.permissions = ['doodle', 'type']

CREATE UNIQUE in neo4j produces duplicate nodes

According to the neo4j documentation:
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.
This sounds great, but CREATE UNIQUE doesn't seem to follow the 'least possible change' rule. e.g., here is some Cypher to create two people:
CREATE (n:Person {name: 'Alice'})
CREATE (n:Person {name: 'Bob'})
CREATE INDEX ON :Person(name)
and here's two CREATE UNIQUE statements, to create a relationship between those people. Since both people already exist in the graph, only the relationships should be newly created:
MATCH (a:Person {name: 'Alice'})
CREATE UNIQUE (a)-[:knows]->(b:Person {name: 'Bob'})
RETURN a
MATCH (a:Person {name: 'Alice'})
CREATE UNIQUE (a)<-[:knows]-(b:Person {name: 'Bob'})
RETURN a
After this, the graph should look like
(Alice)<---KNOWS--->(Bob).
But when you run a MATCH query:
MATCH (a:Person)
RETURN a
it seems that the graph now looks like
(Bob)
(Bob)--KNOWS-->(Alice)--KNOWS-->(Bob);
two extra Bobs have been created.
I looked a bit through the other Cypher commands, but none of them seem intended for this use case: create a link between existing node A and existing node B if B exists, and otherwise create a link between existing node A and a newly created node B. How can this problem best be solved within the Cypher framework?
This query should do what you want (if you always want to end up with a single knows relationship between the 2 nodes):
MATCH (a:Person {name: 'Alice'})
MERGE (b:Person {name: 'Bob'})
MERGE (a)-[:knows]->(b)
RETURN a;
Here is how you can do it with CREATE UNIQUE
MATCH (a:Person {name: 'Alice'}), (b:Person {name:'Bob'})
CREATE UNIQUE (a)-[:knows]->(b), (b)-[:knows]->(a)
You need 2 match clauses otherwise you are always creating the node in the CREATE UNIQUE statement, not matching existing nodes.

neo4j cypher joining 2 nodes merge

I have 2 node tags: User, Tag.
Lets say that I have a user node that exists.
Is it possible to match that node,
and then if the tag exists merge between them,
and if the tag doesn't exist create the tag.
I tryed:
MATCH (n:User {name: "user"}) MERGE (n)-[r:follow]->(tag:Tag {name: "notexist")
In the above example it creates the node "notexist" and the relationship.
But if I have a node that is named "notexist" it doesn't merge, instead it creates another tag
named "notexist"
thank you
Lee,
Here's how to do this.
MATCH(n:User {name: 'user'})
WITH n
MERGE (t:Tag {name: 'notexist'})
WITH n, t
MERGE (n)-[r:follow]->(t);
Grace and peace,
Jim

Resources