After some more testing, I don't think I understand how to use OPTIONAL 
MATCH statements correctly.

I have a query to find a bunch of contacts that a user has access to within 
a team.

  PROFILE
  MATCH (:user { id:"foobar" 
})-[:CONTACT]->(uc:contact)-[:CONTACT]->(ur:role)
  WHERE HAS(ur.teamid)
  WITH uc, ur

  MATCH (c:contact {teamid: uc.teamid})-[:CONTACT]->(cr:role)
  WHERE (ur.name IN ["Owners", "Admins"]) OR
        (ur.name = "Employees" AND NOT cr.name = "Clients") OR
        (cr:projectrole AND 
(uc)-[:CONTACT*1..3]->(:projectrole)<-[:CONTACT*0..2]-(cr)) OR
        (c.id = uc.id)
  WITH DISTINCT c, {accessedby: uc.id, accessedrole: ur.name} AS r

  MATCH (c)-[:CONTACT]->(cr:role {teamid: c.teamid})
  WITH c, {
    accessedrole: r.accessedrole, accessedby: r.accessedby,
    role: cr.name
    } AS r

  RETURN c, r LIMIT 10

After running it a few times to make sure that the statement is cached, it 
takes 587 db hits and 118 ms to execute.  I then try and add a simple 
OPTIONAL MATCH query to return all of the phone numbers associated with the 
contacts.  There are 670 nodes in the (c) collection and I'm trying to just 
say 'hey, if the contact has some phone numbers associated with them, get 
me those phone numbers'.  The part in bold below is what was added.

  PROFILE
  MATCH (:user { id:"foobar" 
})-[:CONTACT]->(uc:contact)-[:CONTACT]->(ur:role)
  WHERE HAS(ur.teamid)
  WITH uc, ur

  MATCH (c:contact {teamid: uc.teamid})-[:CONTACT]->(cr:role)
  WHERE (ur.name IN ["Owners", "Admins"]) OR
        (ur.name = "Employees" AND NOT cr.name = "Clients") OR
        (cr:projectrole AND 
(uc)-[:CONTACT*1..3]->(:projectrole)<-[:CONTACT*0..2]-(cr)) OR
        (c.id = uc.id)
  WITH DISTINCT c, {accessedby: uc.id, accessedrole: ur.name} AS r

  MATCH (c)-[:CONTACT]->(cr:role {teamid: c.teamid})
  WITH c, {
    accessedrole: r.accessedrole, accessedby: r.accessedby,
    role: cr.name
    } AS r

*  OPTIONAL MATCH (c)-[:PHONE]->(p:phone)*
*  WITH c, {*
*    accessedrole: r.accessedrole, accessedby: r.accessedby, role: r.role, 
 *
*    phones: EXTRACT(x IN COLLECT(p) | { id: x.id, object: x.object,number: 
x.number, description: x.description })*
*    } AS r*

  RETURN c, r LIMIT 10

This new query now requires 48,000 db hits and 947ms to complete.  Somehow 
finding a collection of 670 contacts took 100ms but seeing if those same 
contacts had phone numbers took 10x longer and took 100x the db hits.  The 
problem that I am running into is that I also need to look for optional 
addresses and tags which altogether is taking over a minute to complete.

Can anybody help me re-write this query to be in line with best practices? 
 What is the right strategy for matching a node along with optional child 
nodes?

Thanks!


-- 
You received this message because you are subscribed to the Google Groups 
"Neo4j" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to