That's a step in the right direction.
UNWIND apoc.trigger.nodesByLabel($assignedLabels, 'Enrollment') AS node
MERGE (p1:SPerson { name: node.name, cell: node.cell, created_at: node.created_at})
WITH p1, node
MATCH (n:SPerson) # are you trying to get a total of all nodes with the :SPerson label?
WITH node, COUNT(n) as size
At this point, you only have 2 variables in context: node
, and size
, where size
will always be the count of MATCH(:SPerson)
. I suspect you are instead attempting to count the number of matching :SPerson
nodes, for which you only need the p1 variable.
Your existing query is again, doing nothing with the p1 variable you first create, and instead find it a second time within the do.when block.
Instead:
WITH p1, node, COUNT(p1) as size
CALL apoc.do.when( size>3 ,
'
MATCH (c:Course {name: \"Paradigm Shifting 101\"})
MERGE (p1)-[:Waitlist]->(c)
'
...
That should be all you really need there, to do what it looks like you're trying to do with the code, but several things still escape me. For instance, why does it matter the count of SPeople, and why don't you have the course-name in the :Enrollment node?
Since you've put some effort into it though, I'll give you something functional, but I strongly advise you carefully analyze why this works, and try to better understand exactly what yours was doing differently.
I'll assume the course-name is in the :Enrollment
node.
UNWIND apoc.trigger.nodesByLabel($assignedLabels, 'Enrollment') AS node
MERGE (p1:SPerson { name: node.name, cell: node.cell, created_at: node.created_at})
WITH p1, node
MATCH (c:Course {name: node.course_name})<-[:Enrolled]-(n:SPerson)
WITH node, p1, c, COUNT(n) as size
# DO WHEN size (number of currently enrolled) <= 4 (no more than 4 enrolled at one time?)
MERGE (p1)-[:Enrolled]->(c) // MERGE to prevent re-adding the same person multiple times
DETACH DELETE node
# ELSE
MERGE (p1)-[:Waitlist]->(c)
DETACH DELETE node
It seems you're struggling a bit with variables, and script context. Remember the following simple rules:
- When doing
(variable :Thing)
, every matching node is available in the variable
.
-
WITH
is only sometimes needed, and it specifies exactly which variables will stay in the context.
-
MATCH (a)-[r]-(b) WITH a
will drop r
and b
. Only a
will be able to be used in the rest of the script.
- MATCH early, then operate on the variables.
- If you're repeatedly calling
MATCH
to find a reference to a node that you've previously had a reference to, you're doing something wrong. Worse, if you do a single DETACH
or DELETE
on that node, between the MATCH
statements for it, you're setting yourself up for some serious problems in the transaction.
A better way.
It looks like you're trying to handle a student request to enroll in a class. If we adjust some terms to reflect better graph design, things will be simplified. Labels are singular nouns, and rels are verbs.
(s:Student {id, name})
(c:Class {id, name, max_students})
(e:Enrollment {student_id, student_name, class_id})
(s)<-[:Applying]-(a)
(s)-[:Enrolled]->(c)
(s)-[:Waiting]->(c)
Rather than going all fancy with triggers, we can handle this with a MERGE when creating the Enrollment:
MATCH (s:Student: {id: 123}), (c:Class {id:456})<-[:Enrolled]-(current:Student)
MERGE (e:Enrollment {student_id: s.id, class_id: c.id})
WITH s, c, a, count(current) as numEnrolled
CALL apoc.do.when(
numEnrolled <=4,
"MERGE (s)-[:Enrolled]->(c)",
"MERGE (s)-[:Waiting]->(c)"
)
DETACH DELETE Enrollment;
This makes it clear that even the Enrollment label itself is unnecessary, if we handle this when attempting to create the Enrollment to begin with:
:params {student_id: 123, class_id: 456}
MATCH (s:Student: {id: $student_id}), (c:Class {id: $class_id})<-[:Enrolled]-(current:Student)
WITH s, c, count(current) as numEnrolled
CALL apoc.do.when(
numEnrolled <=4,
"MERGE (s)-[:Enrolled]->(c)",
"MERGE (s)-[:Waiting]->(c)"
)