add cypher to cloud skills
This commit is contained in:
381
.claude/skills/cypher/references/common-mistakes.md
Normal file
381
.claude/skills/cypher/references/common-mistakes.md
Normal file
@@ -0,0 +1,381 @@
|
||||
# Common Cypher Mistakes and How to Avoid Them
|
||||
|
||||
## Clause Ordering Errors
|
||||
|
||||
### MATCH After CREATE Without WITH
|
||||
|
||||
**Error**: `Invalid input 'MATCH': expected ... WITH`
|
||||
|
||||
```cypher
|
||||
// WRONG
|
||||
CREATE (e:Event {id: $id})
|
||||
MATCH (ref:Event {id: $refId}) // ERROR!
|
||||
CREATE (e)-[:REFERENCES]->(ref)
|
||||
|
||||
// CORRECT - Use WITH to transition
|
||||
CREATE (e:Event {id: $id})
|
||||
WITH e
|
||||
MATCH (ref:Event {id: $refId})
|
||||
CREATE (e)-[:REFERENCES]->(ref)
|
||||
```
|
||||
|
||||
**Rule**: After CREATE, you must use WITH before MATCH.
|
||||
|
||||
### WHERE After WITH Without Carrying Variables
|
||||
|
||||
**Error**: `Variable 'x' not defined`
|
||||
|
||||
```cypher
|
||||
// WRONG - 'a' is lost
|
||||
MATCH (a:Author), (e:Event)
|
||||
WITH e
|
||||
WHERE a.pubkey = $pubkey // ERROR: 'a' not in scope
|
||||
|
||||
// CORRECT - Include all needed variables
|
||||
MATCH (a:Author), (e:Event)
|
||||
WITH a, e
|
||||
WHERE a.pubkey = $pubkey
|
||||
```
|
||||
|
||||
**Rule**: WITH resets the scope. Include all variables you need.
|
||||
|
||||
### ORDER BY Without Aliased Return
|
||||
|
||||
**Error**: `Invalid input 'ORDER': expected ... AS`
|
||||
|
||||
```cypher
|
||||
// WRONG in some contexts
|
||||
RETURN n.name
|
||||
ORDER BY n.name
|
||||
|
||||
// SAFER - Use alias
|
||||
RETURN n.name AS name
|
||||
ORDER BY name
|
||||
```
|
||||
|
||||
## MERGE Mistakes
|
||||
|
||||
### MERGE on Complex Pattern Creates Duplicates
|
||||
|
||||
```cypher
|
||||
// DANGEROUS - May create duplicate nodes
|
||||
MERGE (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'})
|
||||
|
||||
// CORRECT - MERGE nodes separately first
|
||||
MERGE (a:Person {name: 'Alice'})
|
||||
MERGE (b:Person {name: 'Bob'})
|
||||
MERGE (a)-[:KNOWS]->(b)
|
||||
```
|
||||
|
||||
**Rule**: MERGE simple patterns, not complex ones.
|
||||
|
||||
### MERGE Without Unique Property
|
||||
|
||||
```cypher
|
||||
// DANGEROUS - Will keep creating nodes
|
||||
MERGE (p:Person) // No unique identifier!
|
||||
SET p.name = 'Alice'
|
||||
|
||||
// CORRECT - Provide unique key
|
||||
MERGE (p:Person {email: $email})
|
||||
SET p.name = 'Alice'
|
||||
```
|
||||
|
||||
**Rule**: MERGE must have properties that uniquely identify the node.
|
||||
|
||||
### Missing ON CREATE/ON MATCH
|
||||
|
||||
```cypher
|
||||
// LOSES context of whether new or existing
|
||||
MERGE (p:Person {id: $id})
|
||||
SET p.updated_at = timestamp() // Always runs
|
||||
|
||||
// BETTER - Handle each case
|
||||
MERGE (p:Person {id: $id})
|
||||
ON CREATE SET p.created_at = timestamp()
|
||||
ON MATCH SET p.updated_at = timestamp()
|
||||
```
|
||||
|
||||
## NULL Handling Errors
|
||||
|
||||
### Comparing with NULL
|
||||
|
||||
```cypher
|
||||
// WRONG - NULL = NULL is NULL, not true
|
||||
WHERE n.email = null // Never matches!
|
||||
|
||||
// CORRECT
|
||||
WHERE n.email IS NULL
|
||||
WHERE n.email IS NOT NULL
|
||||
```
|
||||
|
||||
### NULL in Aggregations
|
||||
|
||||
```cypher
|
||||
// count(NULL) returns 0, collect(NULL) includes NULL
|
||||
MATCH (n:Person)
|
||||
OPTIONAL MATCH (n)-[:BOUGHT]->(p:Product)
|
||||
RETURN n.name, count(p) // count ignores NULL
|
||||
```
|
||||
|
||||
### NULL Propagation in Expressions
|
||||
|
||||
```cypher
|
||||
// Any operation with NULL returns NULL
|
||||
WHERE n.age + 1 > 21 // If n.age is NULL, whole expression is NULL (falsy)
|
||||
|
||||
// Handle with coalesce
|
||||
WHERE coalesce(n.age, 0) + 1 > 21
|
||||
```
|
||||
|
||||
## List and IN Clause Errors
|
||||
|
||||
### Empty List in IN
|
||||
|
||||
```cypher
|
||||
// An empty list never matches
|
||||
WHERE n.kind IN [] // Always false
|
||||
|
||||
// Check for empty list in application code before query
|
||||
// Or use CASE:
|
||||
WHERE CASE WHEN size($kinds) > 0 THEN n.kind IN $kinds ELSE true END
|
||||
```
|
||||
|
||||
### IN with NULL Values
|
||||
|
||||
```cypher
|
||||
// NULL in the list causes issues
|
||||
WHERE n.id IN [1, NULL, 3] // NULL is never equal to anything
|
||||
|
||||
// Filter NULLs in application code
|
||||
```
|
||||
|
||||
## Relationship Pattern Errors
|
||||
|
||||
### Forgetting Direction
|
||||
|
||||
```cypher
|
||||
// WRONG - Creates both directions
|
||||
MATCH (a)-[:FOLLOWS]-(b) // Undirected!
|
||||
|
||||
// CORRECT - Specify direction
|
||||
MATCH (a)-[:FOLLOWS]->(b) // a follows b
|
||||
MATCH (a)<-[:FOLLOWS]-(b) // b follows a
|
||||
```
|
||||
|
||||
### Variable-Length Without Bounds
|
||||
|
||||
```cypher
|
||||
// DANGEROUS - Potentially explosive
|
||||
MATCH (a)-[*]->(b) // Any length path!
|
||||
|
||||
// SAFE - Set bounds
|
||||
MATCH (a)-[*1..3]->(b) // 1 to 3 hops max
|
||||
```
|
||||
|
||||
### Creating Duplicate Relationships
|
||||
|
||||
```cypher
|
||||
// May create duplicates
|
||||
CREATE (a)-[:KNOWS]->(b)
|
||||
|
||||
// Idempotent
|
||||
MERGE (a)-[:KNOWS]->(b)
|
||||
```
|
||||
|
||||
## Performance Mistakes
|
||||
|
||||
### Cartesian Products
|
||||
|
||||
```cypher
|
||||
// WRONG - Cartesian product
|
||||
MATCH (a:Person), (b:Product)
|
||||
WHERE a.id = $personId AND b.id = $productId
|
||||
CREATE (a)-[:BOUGHT]->(b)
|
||||
|
||||
// CORRECT - Single pattern or sequential
|
||||
MATCH (a:Person {id: $personId})
|
||||
MATCH (b:Product {id: $productId})
|
||||
CREATE (a)-[:BOUGHT]->(b)
|
||||
```
|
||||
|
||||
### Late Filtering
|
||||
|
||||
```cypher
|
||||
// SLOW - Filters after collecting everything
|
||||
MATCH (e:Event)
|
||||
WITH e
|
||||
WHERE e.kind = 1 // Should be in MATCH or right after
|
||||
|
||||
// FAST - Filter early
|
||||
MATCH (e:Event)
|
||||
WHERE e.kind = 1
|
||||
```
|
||||
|
||||
### Missing LIMIT with ORDER BY
|
||||
|
||||
```cypher
|
||||
// SLOW - Sorts all results
|
||||
MATCH (e:Event)
|
||||
RETURN e
|
||||
ORDER BY e.created_at DESC
|
||||
|
||||
// FAST - Limits result set
|
||||
MATCH (e:Event)
|
||||
RETURN e
|
||||
ORDER BY e.created_at DESC
|
||||
LIMIT 100
|
||||
```
|
||||
|
||||
### Unparameterized Queries
|
||||
|
||||
```cypher
|
||||
// WRONG - No query plan caching, injection risk
|
||||
MATCH (e:Event {id: '" + eventId + "'})
|
||||
|
||||
// CORRECT - Use parameters
|
||||
MATCH (e:Event {id: $eventId})
|
||||
```
|
||||
|
||||
## String Comparison Errors
|
||||
|
||||
### Case Sensitivity
|
||||
|
||||
```cypher
|
||||
// Cypher strings are case-sensitive
|
||||
WHERE n.name = 'alice' // Won't match 'Alice'
|
||||
|
||||
// Use toLower/toUpper for case-insensitive
|
||||
WHERE toLower(n.name) = toLower($name)
|
||||
|
||||
// Or use regex with (?i)
|
||||
WHERE n.name =~ '(?i)alice'
|
||||
```
|
||||
|
||||
### LIKE vs CONTAINS
|
||||
|
||||
```cypher
|
||||
// There's no LIKE in Cypher
|
||||
WHERE n.name LIKE '%alice%' // ERROR!
|
||||
|
||||
// Use CONTAINS, STARTS WITH, ENDS WITH
|
||||
WHERE n.name CONTAINS 'alice'
|
||||
WHERE n.name STARTS WITH 'ali'
|
||||
WHERE n.name ENDS WITH 'ice'
|
||||
|
||||
// Or regex for complex patterns
|
||||
WHERE n.name =~ '.*ali.*ce.*'
|
||||
```
|
||||
|
||||
## Index Mistakes
|
||||
|
||||
### Constraint vs Index
|
||||
|
||||
```cypher
|
||||
// Constraint (also creates index, enforces uniqueness)
|
||||
CREATE CONSTRAINT foo IF NOT EXISTS FOR (n:Node) REQUIRE n.id IS UNIQUE
|
||||
|
||||
// Index only (no uniqueness enforcement)
|
||||
CREATE INDEX bar IF NOT EXISTS FOR (n:Node) ON (n.id)
|
||||
```
|
||||
|
||||
### Index Not Used
|
||||
|
||||
```cypher
|
||||
// Index on n.id won't help here
|
||||
WHERE toLower(n.id) = $id // Function applied to indexed property!
|
||||
|
||||
// Store lowercase if needed, or create computed property
|
||||
```
|
||||
|
||||
### Wrong Composite Index Order
|
||||
|
||||
```cypher
|
||||
// Index on (kind, created_at) won't help query by created_at alone
|
||||
MATCH (e:Event) WHERE e.created_at > $since // Index not used
|
||||
|
||||
// Either create single-property index or query by kind too
|
||||
CREATE INDEX event_created_at FOR (e:Event) ON (e.created_at)
|
||||
```
|
||||
|
||||
## Transaction Errors
|
||||
|
||||
### Read After Write in Same Transaction
|
||||
|
||||
```cypher
|
||||
// In Neo4j, reads in a transaction see the writes
|
||||
// But be careful with external processes
|
||||
CREATE (n:Node {id: 'new'})
|
||||
WITH n
|
||||
MATCH (m:Node {id: 'new'}) // Will find 'n'
|
||||
```
|
||||
|
||||
### Locks and Deadlocks
|
||||
|
||||
```cypher
|
||||
// MERGE takes locks; avoid complex patterns that might deadlock
|
||||
// Bad: two MERGEs on same labels in different order
|
||||
Session 1: MERGE (a:Person {id: 1}) MERGE (b:Person {id: 2})
|
||||
Session 2: MERGE (b:Person {id: 2}) MERGE (a:Person {id: 1}) // Potential deadlock
|
||||
|
||||
// Good: consistent ordering
|
||||
Session 1: MERGE (a:Person {id: 1}) MERGE (b:Person {id: 2})
|
||||
Session 2: MERGE (a:Person {id: 1}) MERGE (b:Person {id: 2})
|
||||
```
|
||||
|
||||
## Type Coercion Issues
|
||||
|
||||
### Integer vs String
|
||||
|
||||
```cypher
|
||||
// Types must match
|
||||
WHERE n.id = 123 // Won't match if n.id is "123"
|
||||
WHERE n.id = '123' // Won't match if n.id is 123
|
||||
|
||||
// Use appropriate parameter types from Go
|
||||
params["id"] = int64(123) // For integer
|
||||
params["id"] = "123" // For string
|
||||
```
|
||||
|
||||
### Boolean Handling
|
||||
|
||||
```cypher
|
||||
// Neo4j booleans vs strings
|
||||
WHERE n.active = true // Boolean
|
||||
WHERE n.active = 'true' // String - different!
|
||||
```
|
||||
|
||||
## Delete Errors
|
||||
|
||||
### Delete Node With Relationships
|
||||
|
||||
```cypher
|
||||
// ERROR - Node still has relationships
|
||||
MATCH (n:Person {id: $id})
|
||||
DELETE n
|
||||
|
||||
// CORRECT - Delete relationships first
|
||||
MATCH (n:Person {id: $id})
|
||||
DETACH DELETE n
|
||||
```
|
||||
|
||||
### Optional Match and Delete
|
||||
|
||||
```cypher
|
||||
// WRONG - DELETE NULL causes no error but also doesn't help
|
||||
OPTIONAL MATCH (n:Node {id: $id})
|
||||
DELETE n // If n is NULL, nothing happens silently
|
||||
|
||||
// Better - Check existence first or handle in application
|
||||
MATCH (n:Node {id: $id})
|
||||
DELETE n
|
||||
```
|
||||
|
||||
## Debugging Tips
|
||||
|
||||
1. **Use EXPLAIN** to see query plan without executing
|
||||
2. **Use PROFILE** to see actual execution metrics
|
||||
3. **Break complex queries** into smaller parts to isolate issues
|
||||
4. **Check parameter types** - mismatched types are a common issue
|
||||
5. **Verify indexes exist** with `SHOW INDEXES`
|
||||
6. **Check constraints** with `SHOW CONSTRAINTS`
|
||||
Reference in New Issue
Block a user