Hi,

I'm not sure if this is the right place to submit this.  I was going to 
open an FR ticket on github but changed my mind because I thought maybe 
it's better to have a discussion here first.

I've run into a couple of places where being able to say something like
    match (n ....) /* criteria doesn't involve binding an identifier n2 */
    where n.prop > threshold or ( (n)-->(n2:label{qualifier:"value"}) and 
n2.prop < threshold )
would make the query a lot easier to read.  I'm aware that, in the case of 
'OR', I could use a union after using 2 separate match clauses.  And that's 
what I've been going along with, until now when I need to dynamically 
translate a user query into Cypher.  Here using union can become very 
complex, as the relationships can nest arbitrary levels deep.  But if we 
had a syntax that can bind new identifiers in predicates, it would be very 
easy and, more importantly, very readable.

I've prepared a few simple use cases below.  (See attached image of the 
model)

* Data Set

  Below creates a set of 7 nodes consisting of 4 circles, 2 squares, and 1 
triangle.
  2 circles point to 2 squares, 1 circle point to the triangle, and another 
circle is dangling.

create (:circle{id:1})-[:uses]->(:square{id:1});
create (:circle{id:2})-[:uses]->(:square{id:2});
create (:circle{id:3})-[:uses]->(:triangle{id:3});
create (:circle{id:4});

* Verification

neo4j-sh (?)$ match (c:circle) optional match (c)-[r]->(n) return c, 
labels(c), r, n, labels(n);
+--------------------------------------------------------------------------+
| c              | labels(c)  | r          | n              | labels(n)    |
+--------------------------------------------------------------------------+
| Node[10]{id:1} | ["circle"] | :uses[7]{} | Node[11]{id:1} | ["square"]   |
| Node[12]{id:2} | ["circle"] | :uses[8]{} | Node[13]{id:2} | ["square"]   |
| Node[14]{id:3} | ["circle"] | :uses[9]{} | Node[15]{id:3} | ["triangle"] |
| Node[16]{id:4} | ["circle"] | <null>     | <null>         | <null>       |
+--------------------------------------------------------------------------+

* Queries

1) Circles that don't point to any Squares
    This is easy and can be supported with the current syntax.

neo4j-sh (?)$ match (c:circle) where not (c)-->(:square) return c;


+----------------+
| c              |
+----------------+
    | Node[14]{id:3} |
    | Node[16]{id:4} |
+----------------+

2) Circles that don't point Square(1)
    This can also be accomplished using the current syntax.  So path is 
already supported; the only thing missing is to bind an identifier which 
would allow filtering with additional predicate expressions.

neo4j-sh (?)$ match (c:circle) where not (c)-->(:square{id:1}) return c;
+----------------+
| c              |
+----------------+
| Node[12]{id:2} |
| Node[14]{id:3} |
| Node[16]{id:4} |
+----------------+

3) Circles that point to Square(1) or with id(4)
    Here it's starting to get hairy.  Union queries may also become grossly 
inefficient if the result sets are large.  This is where identifier-binding 
in predicates can help make query more efficient and maybe easier to read 
also.

neo4j-sh (?)$ match (c:circle{id:4}) return c
> union match (c:circle)-->(s:square{id:1}) return c;
+----------------+
| c              |
+----------------+
| Node[16]{id:4} |
| Node[10]{id:1} |
+----------------+

    Would like to say
        match (c:circle) where (c.id=4) or ( (c)-->(s:square{id:1}) ) 
return c

4) (Circle, Square) where Circle is either id(4) or points to Squares with 
id < 4
    This is where the union query is beginning to deteriorate in 
comprehensibility.  One has to remember to use optional match.  And I don't 
know what it would look like, if the optional match is 2 or 3 levels deep. 
 Now imagine this is a portion of a larger query, where the 'c' nodes are 
found by matching in another pattern.  Using the union would require one to 
duplicate that code in all the subsets.  Having more shared predicates 
would have the same effect.

neo4j-sh (?)$ match (c:circle)-->(s:square) where s.id < 4 return c,s
> union match (c:circle{id:4}) optional match (c)-->(s) return c,s;
+---------------------------------+
| c              | s              |
+---------------------------------+
| Node[10]{id:1} | Node[11]{id:1} |
| Node[12]{id:2} | Node[13]{id:2} |
| Node[16]{id:4} | <null>         |
+---------------------------------+


Hope that was clear.  And sorry for the long post.

I also would be more than happy to help implement this if it's not too 
difficult and someone can point me to the right place to start -- it'd be a 
feature that I'd really use a lot.

Cheers,
Kai

-- 
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