Intermediate Cypher -2

let’s tackle relationship direction and optional matches in Neo4j. 🚀


🔹 Relationship Direction

In Neo4j, relationships are directed (→ or ←).
But whether direction matters depends on your query.

Example: Explicit Direction

MATCH (u:User {name: "Alice"})-[:WORKS_ON]->(p:Project) RETURN u, p

👉 Finds only projects where Alice works on the project.

If you reverse:

MATCH (u:User {name: "Alice"})<-[:WORKS_ON]-(p:Project)

👉 Looks for projects that work on Alice (usually makes no sense).


Example: Ignore Direction

If you don’t care about direction:

MATCH (u:User {name: "Alice"})-[:WORKS_ON]-(p:Project) RETURN u, p

👉 Matches regardless of arrow direction.
Useful when relationships are logically undirected (like "FRIENDS_WITH").


📌 Rule of thumb:

  • Use direction (-->) when the semantics matter (like USER -> WORKS_ON -> PROJECT).

  • Drop direction (--) if it doesn’t matter.


🔹 OPTIONAL MATCH

This is like a LEFT JOIN in SQL.
It tries to match a pattern, but if it’s missing, it still returns the node with null for missing parts.

Example:

MATCH (u:User {name: "Alice"}) OPTIONAL MATCH (u)-[:WORKS_ON]->(p:Project) RETURN u.name, p.name

👉 If Alice works on ProjectX → returns ("Alice", "ProjectX")
👉 If Alice has no project → returns ("Alice", null)


Why it’s useful?

  • To include users without projects.

  • To include apps without owners.

  • To handle missing data gracefully.


⚡ Quick Summary

ConceptWhat it does
Direction (a)-[:REL]->(b)Only matches if direction matches
No direction (a)-[:REL]-(b)Matches both directions
OPTIONAL MATCHReturns result even if no match (like SQL LEFT JOIN)

Let’s go step by step on Pattern Matching Basics in Neo4j.


🔹 Pattern Matching in Cypher

Neo4j queries are written in terms of patterns made of:

  • Nodes: ()

  • Relationships: -[]-

  • Direction: -> or <-

Think of it like drawing a graph with text.


1. Node Only

MATCH (u:User) RETURN u

👉 Matches all nodes with label User.


2. Node with Relationship

MATCH (u:User)-[:WORKS_ON]->(p:Project) RETURN u, p

👉 Matches a User connected by a WORKS_ON relationship to a Project.


3. Relationship Properties

MATCH (u:User)-[r:WORKS_ON {since: 2022}]->(p:Project) RETURN u.name, p.name, r.since

👉 Finds relationships where the since property = 2022.


4. Ignore Relationship Direction

MATCH (u:User)-[:WORKS_ON]-(p:Project) RETURN u, p

👉 Matches both (User)-[:WORKS_ON]->(Project) and (User)<-[:WORKS_ON]-(Project).


5. Longer Patterns

MATCH (u:User)-[:WORKS_ON]->(p:Project)-[:HAS_ACCESS_TO]->(a:Application) RETURN u.name, p.name, a.name

👉 Follows a chain: User → Project → Application.


📌 Pattern syntax in general:

(node)-[relationship]->(node)
  • (node) → Node

  • [:TYPE] → Relationship type

  • -> or <- → Direction


✅ So ()-[]->() just means:
"A node connected to another node via a directed relationship.

 let’s dive into Aggregations in Neo4j (Cypher).
Aggregations are used when you want to group and summarize data — just like GROUP BY in SQL.


🔹 Common Aggregation Functions

1. COUNT() – Count nodes or relationships

MATCH (u:User)-[:WORKS_ON]->(p:Project) RETURN p.name, COUNT(u) AS team_size

👉 Returns each project’s name and the number of users working on it.


2. COLLECT() – Gather values into a list

MATCH (u:User)-[:WORKS_ON]->(p:Project) RETURN p.name, COLLECT(u.name) AS team_members

👉 Groups all users for each project into a list.

Example result:

ProjectX | ["Alice", "Bob", "Charlie"]

3. SUM() – Add numeric values

MATCH (u:User)-[:WORKS_ON]->(p:Project) RETURN p.name, SUM(u.salary) AS total_cost

👉 Calculates total salary of users per project.


4. AVG() – Average numeric values

MATCH (u:User)-[:WORKS_ON]->(p:Project) RETURN p.name, AVG(u.experience) AS avg_experience

👉 Finds average years of experience of users per project.


5. MIN() / MAX()

MATCH (u:User)-[:WORKS_ON]->(p:Project) RETURN p.name, MIN(u.experience) AS junior, MAX(u.experience) AS senior

👉 Returns youngest and most experienced team member for each project.


🔹 GROUPING in Cypher

Unlike SQL’s GROUP BY, Cypher automatically groups by the non-aggregated values in your RETURN.

Example:

MATCH (u:User)-[:WORKS_ON]->(p:Project) RETURN p.name, COUNT(u), COLLECT(u.name)

👉 Here p.name is the grouping key.
Each project gets its count + list of users.


🔹 Combining Aggregations

You can mix multiple:

MATCH (u:User)-[:WORKS_ON]->(p:Project) RETURN p.name, COUNT(u) AS team_size, COLLECT(u.name) AS members, AVG(u.salary) AS avg_salary

Comments