Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
02-11-2020 06:29 AM
Hi, I can't tell what is wrong with my query.
I have a node (KnowledgeEntry) that has an outgoing 'CONTAINS' relationship to multiple nodes of type KnowledgeRecord. The query is used to update a KnowledgeEntry and its Records.
Firstly, I want to set the new KnowledgeEntry values which works perfectly fine. Then I want to delete all KnowledgeRecord nodes that are connected to the KnowledgeEntry.
Then I loop over the new Records and create them and add them to the KnowledgeEntry.
If I run the delete query solely it works perfectly fine. But when I re-add the new KnowledgeRecords in the same query the old KnowledgeRecords won't be deleted. I cannot figure out how to accomplish what I'm trying to do. Do I need to run two separate queries?
Here's my query:
MATCH (knowledgeEntry:KnowledgeEntry) WHERE knowledgeEntry.id = $id
SET knowledgeEntry += {
title: $knowledgeEntry.title
}
/* Here I delete all knowledgeRecords connected to the knowledgeEntry */
WITH knowledgeEntry
OPTIONAL MATCH (knowledgeEntry)-[rel:CONTAINS]->(rec:KnowledgeRecord)
DETACH DELETE rel
/* Here I re-add the new knowledgeRecords */
WITH knowledgeEntry
UNWIND $knowledgeRecords AS record
CREATE (knowledgeRecord:KnowledgeRecord)
SET knowledgeRecord = record
CREATE (knowledgeEntry)-[:CONTAINS]->(knowledgeRecord)
RETURN knowledgeEntry, collect(knowledgeRecord) AS knowledgeRecords;
Solved! Go to Solution.
02-12-2020 11:18 AM
The query itself almost looks fine (though per the discussion, if you want to delete the connected :KnowledgeRecord nodes rather than the relationship between the nodes, you'll want to change which variable you're using for the DETACH DELETE), but you will need to reset the cardinality before you create the new records.
That is, for a specific knowledgeEntry, if there were 5 connected recs to delete, you would still have 5 rows for that knowledgeEntry going into the create part of the query, multiplying the number of nodes created and relationships made. WITH knowledgeEntry
doesn't reset cardinality or deduplicate rows.
You would either need to reset the cardinality with an aggregation or DISTINCT:
WITH knowledgeEntry, count(knowledgeEntry) as ignore
or
WITH DISTINCT knowledgeEntry
You may want to PROFILE a run of this query to see what it's doing. Also, check the id() of the connected nodes before and after this query. If the id()s of the rec nodes before the execution of the query are no longer present in the graph after, then they are getting deleted properly, and something else is going on.
02-11-2020 07:36 AM
If you want to delete the Records: DETACH DELETE rec
If you want to keep the Records, but delete the rel between Entry and Record: DELETE rel
If I assume you want to delete the Records:
WITH knowledgeEntry
OPTIONAL MATCH (knowledgeEntry)-[rel:CONTAINS]->(rec:KnowledgeRecord)
DETACH DELETE rec
WITH knowledgeEntry
UNWIND $knowledgeRecords AS record
CREATE (knowledgeRecord:KnowledgeRecord)
SET knowledgeRecord = record
CREATE (knowledgeEntry)-[:CONTAINS]->(knowledgeRecord)
If you're trying to delete the relationships, the second WITH may be preventing that. So, temporarily mutate the graph.
WITH knowledgeEntry
OPTIONAL MATCH (knowledgeEntry)-[rel:CONTAINS]->(rec:KnowledgeRecord)
SET rel.deleteme = 1
WITH knowledgeEntry
UNWIND $knowledgeRecords AS record
CREATE (knowledgeRecord:KnowledgeRecord)
SET knowledgeRecord = record
CREATE (knowledgeEntry)-[:CONTAINS]->(knowledgeRecord)
WITH knowledgeEntry
MATCH (knowledgeEntry)-[rel:CONTAINS {deleteme: 1}]->()
DELETE rel
02-11-2020 10:50 AM
I want to delete the Records and add the new ones ($knowledgeRecords param represents the new ones)
With the first query you provided the result doesn't change unfortunately.
Actually, every time I run this query the amount of knowledgeRecords that are already connected is multiplied by the length of $knowledgeRecords param.
So if the Entry had two records and I want to replace them with three new records the result is a Entry node with six record nodes.
If the Entry has six record nodes and I want to replace them with five new records the result is a Entry node with 30 record nodes.
Could this be a bug???
02-11-2020 12:05 PM
More likely something odd going on with your id
and this MATCH
clause.
How are you populating the $id
, $knowledgeEntry
, and $knowledgeRecords
parameters?
02-11-2020 12:17 PM
I'm using the java bolt driver api
The params object is a Map:
Map<String, Object>
and it looks like this:
Map.of("id", id, "knowledgeEntry", knowledgeEntry, "knowledgeRecords", records),
When debugging those are my values:
Map<String, Object>
with only one entry so far: String title
List<Map<String, Object>>
and each of the entries has the following properties:String content
String type
Integer order
try (Session session = driver.session()) {
return session.writeTransaction(transaction -> transaction.run(cypher, params).stream()
.map(function)
.collect(Collectors.toList()));
}
KnowledgeEntry and KnowledgeRecords are basically my domain classes converted to a map / list of maps.
Also, i dont know if it is important but in both types of map objects there are some null values.
02-11-2020 01:18 PM
There's enough going on here that the nulls might have some side-effects, but I doubt it. Nothing is deleted until the transaction is complete, so there might be some conflict with that, and your CREATE (knowledgeRecord:KnowledgeRecord)
of a new blank node of the same label. You might want to delete in one command, and create in another.
That said, a little deformation of the graph, and doing the delete at the end, might work. Give it a try.
Avoid duplicate nodes with constraints:
CREATE CONSTRAINT ON (e::KnowledgeEntry) ASSERT e.id IS UNIQUE
Duplicates out of the way - deform, create, delete:
Avoid OPTIONAL MATCH
here, you don't need to delete something that isn't there.
MATCH (e:KnowledgeEntry {id: $id})
SET e.title = $knowledgeEntry.title
WITH e
MATCH (e)-[rel:CONTAINS]->(rec:KnowledgeRecord)
SET rec.deleteMe = 1
WITH e
UNWIND $knowledgeRecords AS record
CREATE (r:KnowledgeRecord)<-[:CONTAINS]-(e)
SET r = record
MATCH (deleteRecord:KnowledgeRecord {deleteMe: 1})
DETACH DELETE deleteRecord
02-12-2020 11:18 AM
The query itself almost looks fine (though per the discussion, if you want to delete the connected :KnowledgeRecord nodes rather than the relationship between the nodes, you'll want to change which variable you're using for the DETACH DELETE), but you will need to reset the cardinality before you create the new records.
That is, for a specific knowledgeEntry, if there were 5 connected recs to delete, you would still have 5 rows for that knowledgeEntry going into the create part of the query, multiplying the number of nodes created and relationships made. WITH knowledgeEntry
doesn't reset cardinality or deduplicate rows.
You would either need to reset the cardinality with an aggregation or DISTINCT:
WITH knowledgeEntry, count(knowledgeEntry) as ignore
or
WITH DISTINCT knowledgeEntry
You may want to PROFILE a run of this query to see what it's doing. Also, check the id() of the connected nodes before and after this query. If the id()s of the rec nodes before the execution of the query are no longer present in the graph after, then they are getting deleted properly, and something else is going on.
All the sessions of the conference are now available online