1

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:

Graph diagram here

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?

ceharep
  • 419
  • 1
  • 5
  • 12

1 Answers1

5

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

enter image description here

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
Christophe Willemsen
  • 19,399
  • 2
  • 29
  • 36
  • Excellent explanation. Very helpful. One follow up - is there a way to return just the `Questions` that are returned as `TRUE`? – ceharep Nov 28 '19 at 06:29