ORDER BY
The ORDER BY clause sorts query results.
Basic Sorting
Ascending Order (Default)
MATCH (u:User)
RETURN u.name, u.age
ORDER BY u.age
Descending Order
MATCH (u:User)
RETURN u.name, u.age
ORDER BY u.age DESC
Explicit Ascending
MATCH (u:User)
RETURN u.name, u.age
ORDER BY u.age ASC
Multiple Sort Columns
MATCH (u:User)
RETURN u.city, u.name, u.age
ORDER BY u.city, u.age DESC, u.name
This sorts by:
1. City (ascending)
2. Then age (descending) within each city
3. Then name (ascending) for same city and age
Sort by Expression
Computed Values
MATCH (u:User)
RETURN u.firstName, u.lastName
ORDER BY u.firstName + ' ' + u.lastName
Function Results
MATCH (u:User)
RETURN u.name, u.email
ORDER BY toLower(u.email)
Aggregations
MATCH (u:User)-[:POSTED]->(p:Post)
RETURN u.name, count(p) AS posts
ORDER BY posts DESC
Sort by Relationship Properties
MATCH (a:User)-[r:KNOWS]->(b:User)
WHERE a.name = 'Alice'
RETURN b.name, r.since
ORDER BY r.since DESC
Sort with Aliases
MATCH (u:User)
RETURN u.name AS userName, u.age AS userAge
ORDER BY userAge DESC, userName
Null Handling
NULL values sort to the end by default:
MATCH (u:User)
RETURN u.name, u.age
ORDER BY u.age
// NULLs appear last
Descending order:
MATCH (u:User)
RETURN u.name, u.age
ORDER BY u.age DESC
// NULLs appear first
Sort by Multiple Properties
Primary and Secondary Sort
MATCH (p:Post)
RETURN p.title, p.likes, p.created
ORDER BY p.likes DESC, p.created DESC
Mixed Ascending/Descending
MATCH (u:User)
RETURN u.country, u.city, u.name
ORDER BY u.country ASC, u.city DESC, u.name ASC
Sort with LIMIT
MATCH (p:Post)
RETURN p.title, p.likes
ORDER BY p.likes DESC
LIMIT 10
Sort Aggregated Results
Sort by Count
MATCH (u:User)-[:POSTED]->(p:Post)
RETURN u.name, count(p) AS postCount
ORDER BY postCount DESC
Sort by Average
MATCH (u:User)-[:POSTED]->(p:Post)
RETURN u.name, avg(p.likes) AS avgLikes
ORDER BY avgLikes DESC
Sort by Multiple Aggregations
MATCH (u:User)-[:POSTED]->(p:Post)
RETURN u.name,
count(p) AS posts,
avg(p.likes) AS avgLikes
ORDER BY posts DESC, avgLikes DESC
Case-Insensitive Sorting
MATCH (u:User)
RETURN u.name
ORDER BY toLower(u.name)
Sort by Date/Time
Recent First
MATCH (p:Post)
RETURN p.title, p.created
ORDER BY p.created DESC
Oldest First
MATCH (u:User)
RETURN u.name, u.joinedDate
ORDER BY u.joinedDate ASC
Sort by String Length
MATCH (p:Post)
RETURN p.title
ORDER BY size(p.title) DESC
Sort by Array Size
MATCH (u:User)
RETURN u.name, size(u.tags) AS tagCount
ORDER BY tagCount DESC
Common Patterns
Top N Items
MATCH (p:Post)
RETURN p.title, p.views
ORDER BY p.views DESC
LIMIT 10
Bottom N Items
MATCH (p:Product)
RETURN p.name, p.sales
ORDER BY p.sales ASC
LIMIT 5
Most Active Users
MATCH (u:User)-[:POSTED]->(p:Post)
RETURN u.name, count(p) AS posts
ORDER BY posts DESC
LIMIT 20
Recent Activity
MATCH (u:User)-[:POSTED]->(p:Post)
RETURN u.name, p.title, p.created
ORDER BY p.created DESC
LIMIT 50
Alphabetical List
MATCH (u:User)
RETURN u.name
ORDER BY u.name ASC
Leaderboard
MATCH (u:User)
RETURN u.name, u.score
ORDER BY u.score DESC, u.name ASC
Timeline
MATCH (e:Event)
RETURN e.description, e.timestamp
ORDER BY e.timestamp ASC
-
Create Indexes on Sorted Properties
CREATE INDEX ON :User(age)
// Fast sorting with index
MATCH (u:User)
RETURN u
ORDER BY u.age
-
Limit Before Sorting When Possible
// If you only need top 10, use LIMIT
ORDER BY u.age DESC
LIMIT 10
-
Sort Early in Query
// Good: Sort before expensive operations
MATCH (u:User)
ORDER BY u.created DESC
LIMIT 100
WITH u
// ... more operations
// Bad: Sort after expensive operations
MATCH (u:User)
// ... expensive operations
ORDER BY u.created DESC
-
Avoid Sorting Large Result Sets
// Good: Filter then sort
MATCH (u:User)
WHERE u.active = true
RETURN u
ORDER BY u.name
// Bad: Sort then filter
MATCH (u:User)
ORDER BY u.name
WHERE u.active = true
RETURN u
Sorting NULL Values
Control NULL placement:
// NULLs last (default ascending)
ORDER BY u.age ASC
// NULLs first (default descending)
ORDER BY u.age DESC
// Force NULLs to end
ORDER BY
CASE WHEN u.age IS NULL THEN 1 ELSE 0 END,
u.age
Random Order
MATCH (u:User)
RETURN u
ORDER BY rand()
LIMIT 10
Next Steps