Traversing the Graph While Formatting the Return Statement

I am fairly new to Neo4j and graph databases in general, and I've been experimenting with a feature that seems to simplify my application significantly. After filtering nodes, I’m performing graph traversal inside the return statement, which allows me to return not only the matched nodes but also relational data. For example:

MATCH (p:Person)
RETURN {
  name: p.name,
  workplace: head([(p)-[:WORKS_AT]->(c:Company) | { name: c.name }]),
  friends: [(f:Person)-[:FRIEND_OF]->(p) | { name: f.name }],
}

This approach feels like a great alternative to running multiple queries. However, I’ve noticed that this method tends to slow down the queries significantly, especially as the result set grows. For context:

  • Graph Size: The result set involves about 100-1000 nodes, and the execution time is typically +1 second.
  • Indexes: I’m curious if indexes are even relevant in this scenario. Does the traversal performed inside the return statement depend on indexes, or is it simply following relations on nodes already in memory?
  • Version and Environment: I’m using Neo4j 5.22

I’m wondering if this is a common practice or if it’s an antipattern that could be causing the slowdown. Are there any tips or alternative approaches to speed up these types of queries?

Additionally, if anyone has insights on how indexes might play a role in this scenario, that would be greatly appreciated.

Thank you for your help!

I like your query style.

Short answer, you can profile your qureis and compare dbhits: Execution plans and query tuning - Cypher Manual

Small tips and tricks.

  1. If your relationship types are "correct" you can remove filtering on :Company and :Person (make patterns as simple as possible = less work)
  2. Slice collections so you control the number of friends returned
  3. There is also a collect { subquery } clause COLLECT subqueries - Cypher Manual (and count {subquery} ) that can come in handy
  4. Limit the results
MATCH (p:Person)
RETURN {
  name: p.name,
  workplace: [(p)-[:WORKS_AT]->(c) | { name: c.name }][0],
  friends: [(f)-[:FRIEND_OF]->(p) | { name: f.name }][0..10]
}
LIMIT 10