I am currently implementing a graph database in which persons are allocated to projects (of a customer) using an allocation node. Customers or Projects may or may not exist already, the Allocation node should be unique (each Allocation node can only have one incoming and one outgoing relationship). The code below works, but duplicates the Project->Customer relationship when both already exists in the database. How can I prevent this?
MATCH (p:Person {id:1})
MERGE (c:Customer {id:1})
MERGE (pr:Project {id:1})
CREATE (p)-[:HAS_ALLOCATION]->(a:Allocation)-[:ON_PROJECT]->(pr)-[:HAS_CUSTOMER]->(c)
RETURN a,p,pr,c;
You should try both MERGE and CREATE UNIQUE in place of your CREATE clause and see if that fixes your issue.
Related
My question is regarding how to merge multiple duplicate nodes.
Each node is, as a duplicate, connected to other nodes with a MENTIONED edge.
What I would like to do is to merge those duplicate nodes based on two properties being identical (the properties are entity_type and name so where entity_type=entity_type and name=name then merge those two nodes) and to also be able to preserve the relationships those nodes had pre-merge to other nodes on the new node. So the new merged node might have 2+ relationships to other nodes that the nodes it was merged from had.
Does anyone have any advice on how to structure this query? Thank you very much.
You should use APOC library to do this.
APOC has a procedure apoc.refactor.mergeNodes which can merge multiple duplicate nodes into one node.
All relationships are merged onto that node too.
You can refer the following query to structure yours:
MATCH (p:Entity)
WITH p.name AS name, p.entity_type AS type, collect(p) as nodes
CALL apoc.refactor.mergeNodes(nodes, {properties: {`.*`: 'discard'}}) YIELD node
RETURN count(node) AS new_node_count
I have an empty neo4j database. I want the city{val:"new york"} node to only have one instance, not two. What is the correct way to CREATE these nodes and relationships so that john and sam are pointing to the same city{val:"new york"} node?
CREATE
(p:person{name:"john"}),
(c:city{val:"new york"}),
(p)-[:LIVES_IN]->(c)
CREATE
(p:person{name:"sam"}),
(c:city{val:"new york"}),
(p)-[:LIVES_IN]->(c)
The data I am importing is in a csv file. I need some way to only create the city if it does not already exist. I tried to replace CREATE with MERGE, but the syntax is unclear.
It is simpler (and safer, since you don't always know if the data already exists) to just always use MERGE in cases where there can be duplicate attempts to create data that you want to be unique.
These 2 blocks of Cypher statements will not create duplicate nodes/relationships, even if you reverse the order (or if the DB already has some of the same data).
MERGE (p:person{name:"john"})
MERGE (c:city{val:"new york"})
MERGE (p)-[:LIVES_IN]->(c);
MERGE (p:person{name:"sam"})
MERGE (c:city{val:"new york"})
MERGE (p)-[:LIVES_IN]->(c);
Answering my own question. Each line needs its own MERGE clause.
CREATE
(p:person{name:"john"}),
(c:city{val:"new york"}),
(p)-[:LIVES_IN]->(c)
MERGE (p:person{name:"sam"})
MERGE (c:city{val:"new york"})
MERGE (p)-[:LIVES_IN]->(c)
Good related resource...https://neo4j.com/blog/common-confusions-cypher/
I would like to create a constraint like this:
create constraint on (a:NodeTypeA)-[r:TYPE_OF_REL]->(b:NodeTypeB) ASSERT count(r) < 2
You can kind of get the same result by using MERGE instead of CREATE whenever you create such a relationship. For example:
MATCH (a:NodeTypeA {id: 123}), (b:NodeTypeB {id: 456})
MERGE (a)-[r:TYPE_OF_REL]->(b);
The MERGE will not create the relationship if it already exists.
(Note, however, that duplicate relationships are still possible if multiple MERGE operations can run concurrently. This is not a concern if you are using a neo4j 3.1.2 or later, or the DB is only asked to perform one operation at a time.)
According to the documentation, Neo does not support this.
Due to a unforeseen shutdown (and /or and error in my code) I have relationships in the database without nodes attached to it.
I think what happened was that used a MATCH statement to look up a node and subsequently a MERGE to create a relationship. For some reasons however the Match did not return a results, but the MERGE did create a relationship (apparently with a non existing node). See example below:
MATCH (image:Image {id:{param}.id})
FOREACH (tagName in {param}.tags | MERGE (tag:Tag {tag:tagName}) MERGE (image)-[:IS_TAGGED_AS]->(tag) // Here it creates a relationship even if no matching image is found.
)
When I run a simple query I receive the following message:
While loading relationships for Node[xx] a Relationship[xx] was encountered that had startNode: 0 and endNode: 0, i.e. which had neither start nor end node as the node we're loading relationships for
I can reference the node and the relationship by Id (although the relationship does not return results) but can't Delete them.
Is there anything I can do to fix this?
Ideally I create a query to select all 'bad' relationships and delete them.
I am working on Neo4j 2.3.0.
Are you sure that relationships can be created without nodes? That doesn't make sense to me. The way MERGE works is that it will match a node or relationship if it exists, otherwise it will try create a new one.
If you add PROFILE to the start of your query in the Neo4j Browser, you can see the execution plan for a query. You will see that nodes are matched first and then the relationships are matched and/or created afterwards.
I have two column in csv file, emp_id and mngr_id. The relationship is (emp_id)-[:WORKS_UNDER]->(mngr_id). I want to merge all those nodes where emp_id=mngr_id. How to do that while creating nodes itself?
If I understand correctly, you're looking to ensure that you avoid creating duplicate relationships when iterating over the CSV data and avoid entering a relationship where a person works for themselves.
To avoid creating a relationship where emp_id and mngr_id identify the same person, I would suggest filtering the CSV before processing it to enter the data. It should be much easier to omit any lines in the CSV file where the emp_id and mngr_id are the same value before passing it to Neo4j.
Next, if you're using Cypher to do the importing, something like this may be useful:
MERGE (emp:Person{id:'emp_id'}) MERGE (mgr:Person{id:'mngr_id'}) MERGE (emp)-[:WORKS_UNDER]->(mgr) RETURN emp,mgr
Note that if you run the above query multiple times in a block statement then you'll need unique identifiers for emp and mgr in each query.
Merge is explained well in the Neo4j docs: http://docs.neo4j.org/chunked/stable/query-merge.html