tomasonjo/blogs
Overview
This skill is a practical guide for writing modern Neo4j Cypher read queries that avoid deprecated features and follow current best practices. It targets text2cypher tools and LLMs generating Cypher, emphasizing performance, clarity, and maintainability. The guide covers CALL subqueries for reads, Quantified Path Patterns (QPP), sorting rules, and modern aggregations.
How this skill works
The skill inspects query patterns and recommends modern replacements for removed features (for example elementId() instead of id()). It prescribes explicit WITH clauses, NULL-safe sorting, early filtering inside traversals, and use of CALL subqueries or COLLECT/COUNT/EXISTS subqueries for complex reads. It also suggests QPP for efficient variable-length path traversal.
When to use it
- Migrating legacy Cypher or fixing syntax errors caused by removed features
- Generating read queries from natural language (text2cypher) or LLMs
- Optimizing variable-length or multi-hop traversals for performance
- Building complex read operations that need top-N, aggregation, or nested collections
- Ensuring stable ordering when queries sort by possibly null properties
Best practices
- Replace deprecated functions like id() with elementId() and treat it as a string
- Use explicit WITH clauses for any grouping or mixed aggregate/ non-aggregate expressions
- Always filter NULLs before ORDER BY or use NULLS LAST to avoid unexpected results
- Prefer CALL subqueries for complex reads and maintain clear variable scope
- Use QPP (Quantified Path Patterns) to filter during traversal and limit expansion depth
- Use COUNT{}, EXISTS{}, and COLLECT{} subqueries instead of pattern expressions or size()
Example use cases
- Generate a top-3 earners per department using CALL subqueries with ORDER BY and LIMIT
- Rewrite legacy MATCH queries that use id() and implicit grouping into modern Cypher
- Optimize a variable-length friend-of-friend traversal with QPP and inline node filters
- Count relationships efficiently with COUNT{} instead of size()
- Ensure deterministic sorting for results by adding IS NOT NULL checks before ORDER BY
FAQ
id() was removed; elementId() returns a stable string identifier and must be treated as a string when comparing or storing.
When should I use CALL subqueries?
Use CALL subqueries for complex read logic, nested aggregations, top-N per group, or when you need to limit or order results scoped to a parent node.