You can also do number 3) because you actually don't need "s"
match (c:circle) where (c.id=4) or ( (c)-->(:square{id:1}) ) return c
Only #4 is trickier but still possible, only not so nice to read :)
*I think union is still the better choice here as you combine 2 different
use-cases:*
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;
But you can use a path expression as a collection of paths, which you then
can use in collection predicates (all, any, single, none) , filter,
extract, reduce.
match (c:circle)
where any(p in (c)-->(:square) where last(nodes(p)).id <http://s.id/> < 4)
return c
On Wed, Oct 29, 2014 at 2:12 AM, Kai Chen <[email protected]> wrote:
> 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.
>
--
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.