Which Equipment Depends on This Supply?
Represent equipment and its directed dependencies as nodes and relationships before choosing how to query the connections.
12 sections · 4 questions · 1 coding challenge
The arrow keys move between sections too.
Relationships Became Part of the Stored Model
BOTIE
This changes how we express a dependency question. The relationship is a stored fact we can follow from a known starting asset. It does not make every query faster, and relational tables can represent the same facts with keys and joins.
Sources for this history
The Pump Record Does Not Contain the Whole Answer
P7 depends on supply S1. Another pump, P8, depends on P7. Botie needs to distinguish the supply P7 needs from the equipment that needs P7. A list of asset names cannot express that difference.
We need to store the connection itself, including what it means and which way it points. A graph makes those connected records explicit. We can then ask a question by following the relationships that matter to it.
Invented maintenance records. Python exercises and workshop components expose the mechanism locally. Source-linked Cypher or SPARQL examples require the stated external database setup.
Step 1 of 1
Read the arrows as dependency statements
The arrow means the source requires the target. Follow only the direction the question asks for.
Nodes and properties (3)
- P8 · Pump
- P7 · Pump
- S1 · Supply
- P8 to P7: DEPENDS_ON
- P7 to S1: DEPENDS_ON
Follow the dependency in the requested direction
Type and source filtering retain outgoing dependency facts; projecting target IDs answers which resources this asset directly requires.
Follow the dependency in the requested direction
Botie needs what this pump requires, not everything connected to it.
BOTIE
Result for these records
- 0S1
Follow the operations
1. Equipment graph
Nodes and properties (3)
- P7 · Asset
- S1 · Asset
- P8 · Asset
- P7 to S1: DEPENDS_ON
- P8 to P7: DEPENDS_ON
Inspect the node and relationship records
{ "nodes": [ { "id": "P7", "kind": "Asset" }, { "id": "S1", "kind": "Asset" }, { "id": "P8", "kind": "Asset" } ], "edges": [ { "id": "d1", "source": "P7", "target": "S1", "type": "DEPENDS_ON" }, { "id": "d2", "source": "P8", "target": "P7", "type": "DEPENDS_ON" } ] }2. Read graph relationships
[ { "id": "d1", "source": "P7", "target": "S1", "type": "DEPENDS_ON" }, { "id": "d2", "source": "P8", "target": "P7", "type": "DEPENDS_ON" } ]3. Choose a relationship type
[ { "id": "d1", "source": "P7", "target": "S1", "type": "DEPENDS_ON" }, { "id": "d2", "source": "P8", "target": "P7", "type": "DEPENDS_ON" } ]4. Starting asset ID
P7
5. Choose an endpoint match
[ { "id": "d1", "source": "P7", "target": "S1", "type": "DEPENDS_ON" } ]6. Collect distinct identifiers
- 0S1
7. Result
- 0S1
These components operate on the supplied records in your browser. They do not run a graph database or interpret Cypher.
1. Give each entity a node
A node represents one entity whose identity matters. P7 and S1 are separate assets even if both have the display name “Main unit.” An asset category can be a label, while its status or installation date can be properties.
A label groups nodes; it is not the node’s identity. A node can have several labels in a property graph. Our Python records use kind for one teaching category and id for a stable identifier.
Begin with the things the application must distinguish, rather than turning every cell into a node.
2. Make the relationship a record too
A relationship connects a source node to a target node and has a type such as DEPENDS_ON. Its direction expresses our modelling convention. Properties on that relationship can describe the connection, such as when the dependency became active.
Two relationships may connect the same nodes for different reasons, or represent separate events. Removing them as duplicates without a domain rule can lose information.
The source and target describe the relationship, not which object is more important.
3. Ask a one-hop question before following a chain
For “what does P7 depend on directly?”, find outgoing DEPENDS_ON relationships from P7 and read their target nodes. For “what depends on P7?”, match the incoming direction.
Cypher writes node patterns in parentheses and relationship patterns in brackets. The arrow preserves the convention we drew. RETURN chooses the information to display.
A direct neighbour is one relationship away. It is different from every node reachable through a longer chain.
Run in your own environment
Read P7’s direct dependencies
This is an external Cypher query over the setup graph.
In a fresh Neo4j test database, run CREATE (p:Asset {id:'P7'}), (s:Asset {id:'S1'}), (q:Asset {id:'P8'}), (p)-[:DEPENDS_ON]->(s), (q)-[:DEPENDS_ON]->(p).
Supply parameter asset as the string P7. Use a read-only database role for the query.
MATCH (:Asset {id:$asset})-[:DEPENDS_ON]->(s:Asset)
RETURN DISTINCT s.id AS dependency
ORDER BY dependencyS1 is the result. Reversing the arrow would answer a different question.
Official documentation. Documentation checked .
Check yourself
Questions on Parts 1 to 3
Question 1 of 2
Which node is P7’s direct dependency?
Use the information below.
P8→P7→S1 uses DEPENDS_ON arrows from dependent to required asset.4. Represent the same mechanism with ordinary records
The graph dictionary contains a nodes list and an edges list. Each edge names its source and target by ID. We can inspect the relevant edge records without needing a database server.
This program shows the matching edge identities. The challenge takes the next step and returns distinct dependency IDs instead.
These loops demonstrate the model; database storage and query planning remain separate topics.
Inspect the outgoing edge records
Only the edge whose source is P7 matches.
edges = [{"id": "d1", "source": "P7", "target": "S1", "type": "DEPENDS_ON"}, {"id": "d2", "source": "P8", "target": "P7", "type": "DEPENDS_ON"}]
print([e['id'] for e in edges if e['type']=='DEPENDS_ON' and e['source']=='P7'])['d1']The incoming d2 relationship does not describe a resource P7 requires.
5. Choose graphs because the relationships matter
A graph representation is useful when questions repeatedly follow connected entities, especially through changing numbers of hops. A simple tabular report may be clearer and cheaper in a relational database.
The learning task is to preserve identity, direction and relationship meaning. Storage products differ in constraints, transactions and indexing, so a picture of connected circles is not a complete architecture decision.
We will keep the maintenance question stable while adding the machinery needed to answer it reliably.
Check yourself
Questions on Parts 1 to 5
Question 1 of 2
Can they always be merged into one edge?
Use the information below.
Two relationships connect the same pumps but have different types.Try it with Botie
Build with Botie
Write and run Python