I'm just getting started with neo4j and would like some help trying to solve a problem.
I have a set of Questions
that require information (Slots
) to answer them.
The rules of the graph (i.e. the Slots
required
for each Question
) are shown below:
In a scenario in which I have a set of slots e.g. [Slot A
, Slot B
] I want to be able to check all Questions
that the Slots
are related to e.g. [Question 1
, Question 2
].
I then want to be able to check for which of the Questions
all required
Slots
are available, e.g. [Question 1
]
Is this possible, and if so how should I go about it?
Yes it's possible.
Some data fixtures :
CREATE (q1:Question {name: "Q1"})
CREATE (q2:Question {name: "Q2"})
CREATE (s1:Slot {name: "Slot A"})
CREATE (s2:Slot {name: "Slot B"})
CREATE (s3:Slot {name: "Slot C"})
CREATE (q1)-[:REQUIRES]->(s1)
CREATE (q1)-[:REQUIRES]->(s2)
CREATE (q2)-[:REQUIRES]->(s1)
CREATE (q2)-[:REQUIRES]->(s3)
Find questions related to a slots list :
MATCH p=(q:Question)-[:REQUIRES]->(slot)
WHERE slot.name IN ["Slot A", "Slot B"]
RETURN p
Then, find questions related to a slot list, and return a boolean if the slot list contains all required slots for a question :
MATCH p=(q:Question)-[:REQUIRES]->(slot)
WHERE slot.name IN ["Slot A", "Slot B"]
WITH q, collect(slot) AS slots
RETURN q, ALL(x IN [(q)-[:REQUIRES]->(s) | s] WHERE x IN slots)
╒═════════════╤═══════════════════════════════════════════════════════╕
│"q" │"ALL(x IN [(q)-[:REQUIRES]->(s) | s] WHERE x IN slots)"│
╞═════════════╪═══════════════════════════════════════════════════════╡
│{"name":"Q1"}│true │
├─────────────┼───────────────────────────────────────────────────────┤
│{"name":"Q2"}│false │
└─────────────┴───────────────────────────────────────────────────────┘
A bit of explanation on that part ALL(x IN [(q)-[:REQUIRES]->(s) | s] WHERE x IN slots)
the ALL predicate, will check that the condition for every value in a list is true, for example ALL (x IN [10,20,30] WHERE x > 5)
the extract shortcut syntax, you pass a list, it returns a list of the extracted values, the syntax is extract(x IN <LIST> | <key to extract>)
for example :
extract(x IN [{name: "Chris", age: 38},{name: "John", age: 27}] | x.age)
// equivalent to the shortcut syntax for extract, with square brackets
[x IN [{name: "Chris", age: 38},{name: "John", age: 27}] | x.age]
Will return [38,27]
Combining it now :
For every path, extract the Slot node
[(q)-[:REQUIRES]->(s) | s]
Returns
[s1, s2]
Are every of s1 and s2, in the list of the slot nodes previously collected ?
ALL(x IN [(q)-[:REQUIRES]->(s) | s] WHERE x IN slots)
Return true or false
Return only the questions when true :
MATCH p=(q:Question)-[:REQUIRES]->(slot)
WHERE slot.name IN ["Slot A", "Slot B"]
WITH q, collect(slot) AS slots
WITH q WHERE ALL(x IN [(q)-[:REQUIRES]->(s) | s] WHERE x IN slots)
RETURN q