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.