Just learning about Graph Databases and NEO4J. I assume that the same distinction between compositional and aggregational relationships applies in Graph databases as in other databases.
Creating an aggregational relationship in NEO4J/Cypher, assuming we already have a Country node called 'Italy' in the database, the below query will create a Currency node called 'Euro' if one doesn't already exist and then create a relationship from Italy to Euro if that relationship doesn't already exist...
MATCH (co:Country {name:'Italy'})
MERGE (cu:Currency {name:'Euro'})
MERGE (co)-[cc:COUNTRYCURRENCY]->(cu)
RETURN cc
If there is not already a relationship Italy->Euro but there is already a Currency node 'Euro' (for example because we had already created the Euro for it to be used by another country, eg 'France'), then the above query would not create a second duplicate node called 'Euro'. it would reuse the existing 'Euro' node and create a new relationship to it from 'Italy'. This is correct behaviour for an aggregational relationship.
So say I want to merge a compositional relationship instead. IE If a parent already has a child with specified name/properties then I don't want to create a duplicate so I need to use MERGE. But if the specified parent doesn't have this child yet and there is already a child node for a different parent with the same name/properties as this child node then I want to create a new one in the context of this parent rather than reuse the existing one. So I need to make the whole operation conditional on whether a relationship already exists between the parent and a child having given properties. Is this syntactically possible in a one-liner?
In Neo4j any node is allowed to exist independently, there is no enforcement of a constraint that says the child can only exist while the parent does.
However you can:
Create a whole path as an atomic operation.
Create a child, only if the parent exists.
Delete a parent and any/all of its child relationships.
Meanwhile a single relationship/edge can of course only exist between two nodes/vertices.
Question:
If I understood your question correctly:
The parent definitely exists.
The child maybe exists, for that parent.
Another child that looks the same, but does not belong to this parent, isn't the parent's child.
Solution:
MERGE (p:Person {name: 'Jasper'})
MERGE (p)-[r:HAS_CHILD]-(c:Child {name: 'Kris'})
What happened:
Regardless of whether there was an existing child named 'Kris', with or without a parent, a new child will be created.
Explanation:
Merge matches a whole pattern, so if that exact pattern does not exist, it will be treated as a create.
We have a knowledge base article on Understanding how MERGE works that covers several cases, including the one for this question.
The section in the article starting with "MERGE using combinations of bound and unbound variables for different use cases" covers what you're after. You want to MATCH or MERGE on the parent node, and then MERGE the relationship to the child node:
MERGE (p:Person {name: 'Jasper'})
MERGE (p)-[r:HAS_CHILD]->(c:Person {name: 'Kris'})
...
MERGE is like a MATCH, and if the MATCH fails, then a CREATE. When we already have bound variables (p is bound to a node because of the MERGE on the first line) then that existing bound node will be used, the node for p won't be recreated.
Related
New to Neo4j. I realize this question has a similar title (Creating nodes and relationships at the same time in neo4j) but I believe I'm trying to do something different. Also I would like to avoid using plugins if possible.
Basically I have a 1000 row CSV that looks something like this
FromNodeID ToNodeID type attribute1 attribute2
1 2 1 1234 1235
3 2 1 1234 1235
...
So I want to create the nodes and their relationships. FromNodes and ToNodes have just one property each (ID) and the relationship has 3 properties (type, attribute1 and attribute2). I want each node to be unique but each node can have many relationships (in the example above, node 2 should have 2 relationships).
Here's what I tried to make that work:
load csv with headers from "file:///file.csv" as row
MERGE (FromNode {id:toInteger(row.FromNode)})-[:communicates
{Type:toInteger(row.Type), attribute1:toInteger(row.attribute1),
attribute2:toInteger(row.attribute2)}]->(ToNode
{id:toInteger(row.ToNode)})
I did put a uniqueness constraint on FromNode and ToNode IDs prior to this query.
I expected it to create each node (and not create new nodes when one with the same ID already exists) and create each relationship (with more than one relationship from/to nodes that are specified to have more than one relationship in the CSV).
What actually happened: It seems to have created all the unique nodes. It also created relationships between the nodes but it only put one relationship per node, NOT accounting for some of the nodes which have communications with more than one other node.
I'm confused because it was my understanding that with MERGE it would create a relationship if it did not occur in the database yet so I thought it would create all relationships specified in the CSV
Your MERGE clause, as written, is not specifying a label for either node. Since a uniqueness constraint is associated with both a node label and a node property, if you do not specify a node label during node creation neo4j cannot enforce any uniqueness constraints. So the MERGE is actually creating some duplicate nodes (with no labels). This is also why all the new nodes only have a single relationship.
In Cypher, a node's label must be preceded by a colon. For example, (:Foo {abc:123}) instead of (Foo {abc:123}).
Also, to avoid potential constraint violation errors, you should have separate MERGE clauses for each node.
If the relevant labels are FromNode and ToNode, try this:
LOAD CSV WITH HEADERS FROM "file:///file.csv" AS row
MERGE (f:FromNode {id:toInteger(row.FromNode)})
MERGE (t:ToNode {id:toInteger(row.ToNode)})
MERGE (f)-[:communicates {
Type:toInteger(row.Type), attribute1:toInteger(row.attribute1),
attribute2:toInteger(row.attribute2)}
]->(t)
I am new to Neo4j and am referring to this tutorial.
I am not finding any answer on how to fetch the node name using CQL.
For example:
If I create two nodes like so:
CREATE (Dhawan:player{name: "Shikar Dhawan", YOB: 1985, POB: "Delhi"})
CREATE (Ind:Country {name: "India"})
and then build relationship at a later date using:
CREATE (Dhawan)-[r:BATSMAN_OF]->(Ind)
How do we know the node name: Dhawan or Ind?
Using:
MATCH (n) RETURN n
I am getting back the label name but not the node name!
How do I get all the details of an existing graph DB?
The thing you're calling "the node name" is actually a variable, and is only present for the duration of a single query (or less, if you don't include it in a WITH clause and it goes out of scope). It is never saved to the graph db, and is not persisted data.
In your example, you would only be able to use CREATE (Dhawan)-[r:BATSMAN_OF]->(Ind) (and have those variables refer to your previously created nodes) if the create was performed in the same query where those variables were previously bound (and still in scope).
Otherwise, this would create two new nodes, create the :BATSMAN_OF relationship between them, and bind those variables to the new nodes for the duration of their scope.
I'd like to set a different style/color for relationships in my database that have the property "critical". I assume to do this, I need to update the relationships with a new label called "isCrit" and modify the grass file.
Can anyone help with selecting all relationships with a particular property and create the new label "isCrit"?
Fairly new to neo4j
Can anyone help with selecting all relationships with a particular
property and create the new label "isCrit"?
Neo4j relationships do not have labels. Labels are part of nodes. They can hold more than one label. Relationships have a relationship type. Take a look in the docs about relationships.
Also, relationships can have only one type. This way you cannot add another relationship type to a given relationship. Moreover, currently has no way to change the relationship type. In the cases that you want to change the relationship type you should delete the current relationship and create a new one with the desired type, as described in this answer:
MATCH (n:User {name:"foo"})-[r:REL]->(m:User {name:"bar"})
CREATE (n)-[r2:NEWREL]->(m)
// copy properties, if necessary
SET r2 = r
WITH r
DELETE r
hi how can i transform this SQL Query as CYPHER Query ? :
SELECT n.enginetype, n.Rocket20, n.Yearlong, n.DistanceOn,
FROM TIMETAB AS n
JOIN PLANEAIR AS p ON (n.tailnum = p.tailNum)
If it is requisition before using that query to create any relationship or antyhing please write and help with that one too.. thanks
Here's a good guide for comparing SQL with Cypher and showing the equivalent Cypher for some SQL queries.
If we were to translate this directly, we'd use :PLANEAIR and :TIMETAB node labels (though I'd recommend using better names for these), and we'll need a relationship between them. Let's call it :RELATION.
Joins in SQL tend to be replaced with relationships between nodes, so we'll need to create these patterns in your graph:
(:PLANEAIR)-[:RELATION]->(:TIMETAB)
There are several ways to get your data into the graph, usually through LOAD CSV. The general approach is to MERGE your :PLANEAIR and :TIMETAB nodes with some id or unique property (maybe TailNum?, use ON CREATE SET ... after the MERGE to add the rest of the properties to the node when it's created, and then MERGE the relationship between the nodes.
The MERGE section of the developers manual should be helpful here, though I'd recommend reading through the entire dev manual anyway.
With this in place, the Cypher equivalent query is:
MATCH (p:PLANEAIR)-[:RELATION]->(n:TIMETAB)
RETURN n.Rocket20,p.enginetype, n.year, n.distance
Now this is just a literal translation of your SQL query. You may want to reconsider your model, however, as I'm not sure how much value there is in keeping time-related data for a plane separate from its node. You may just want to have all of the :TIMETAB properties on the :PLANEAIR node and do away with the :TIMETAB nodes completely. Of course your queries and use cases should guide how to model that data best.
EDIT
As far as creating the relationship between :PLANEAIR and :TIMETAB nodes (and again, I recommend using better labels for these, and maybe even keeping all time-related properties on a :Plane node instead of a separate one), provided you already have those nodes created, you'll need to do a joining match, but it will help to have a unique constraints on :PLANEAIR(tailnum) :TIMETAB(tailNum) (or an index, if this isn't supposed to be a unique property):
CREATE CONSTRAINT ON (p:PLANEAIR)
ASSERT p.tailNum IS UNIQUE
CREATE CONSTRAINT ON (n:TIMETAB)
ASSERT n.TailNum IS UNIQUE
Now we're ready to create the relationships
MATCH (p:PLANEAIR)
MATCH (n:TIMETAB)
WHERE p.tailNum = n.tailNum
CREATE (p)-[:RELATION]->(n)
REMOVE n.tailNum
Now that the relationships are created, and :TIMETAB tailNum property removed, we can drop the unique constraint on :TIMETAB(tailNum), since the relationship to :PLANEAIR is all we need.
DROP CONSTRAINT ON (n:TIMETAB)
ASSERT n.tailNum IS UNIQUE
I have a set of nodes which are part of a hierarchy. One node can be related to other node by virtue of child having a parentKey which links to another node. In relational land this would be represented as a 'pigs ear' in an ER diagram.
How can I can generate this relationship between the nodes in neo4j?
I'm quite new to graphs so apologies if I haven't explain it very well.
Thanks
If I understand you correctly, you want to link a "child" node to a "parent" node. That is very easy to do. For instance:
CREATE (child:Person)-[:HAS_PARENT]->(parent:Person)
In this sample data model, we have a Person node label, and a HAS_PARENT relationship type. HAS_PARENT relationships are used to link Person nodes to represent the hierarchy.
If you're talking about already existing nodes, you can match the existing nodes and then use merge to create a relationship.
MATCH (child:SomeLabel) MATCH (parent:SomeOtherLabel)
MERGE (parent)-[:HAS_CHILD]->(child)
You can also use merge when creating new nodes.
See http://neo4j.com/docs/stable/query-merge.html