For an optional match the path expression returns a empty collection if there is no match. So you could test for that.
You can return values by either returning the path, or by using head(extract(p in (c)-->() | last(p))) to return "s" I still think that with your UI, the UNIONs would represent "alternative" use-cases, i.e. alternative execution-paths on the top-level, which should lend themselves nicely to an UI. Michael On Wed, Oct 29, 2014 at 6:33 AM, S. Kai Chen <[email protected]> wrote: > Yes, Wes, that solves the simple case where only 2 nodes are involved. > > What about the situation where 4 or 5 nodes on the path? with a coupe of > OR's? > > It's a bit late for me right now. But I will try come up with a more > concrete example tomorrow. > > Cheers, > Kai > > On Tue, Oct 28, 2014 at 10:28 PM, Wes Freeman <[email protected]> > wrote: > >> How about this? Defer predicates until you match more than you need, then >> double check what you need to confirm in WHERE. >> >> MATCH (c:circle) >> OPTIONAL MATCH (c)-->(s:square) >> WITH c, s >> WHERE c.id = 4 >> OR ((c)-->(s) AND s.id < 4) >> RETURN c,s >> >> Wes >> >> On Wed, Oct 29, 2014 at 1:13 AM, S. Kai Chen <[email protected]> >> wrote: >> >>> Hi, Michael, >>> >>> Thanks for the quick response! And sorry about my own late reply: I had >>> to go to a meeting right after I sent the first post and have just gotten >>> back right now. >>> >>> Interesting suggestion with using path expression and collection >>> predicates. How would you include an optional path here? Is there a way >>> to return the 4th circle, which won't match in the path? >>> >>> I agree union is a clearer way to write it, especially when there are >>> only 2 subsets. However, I'm concerned about situations where one needs to >>> include more subsets, sometimes maybe 4 or 5 or more. With compound >>> criteria, it's easier to read when all the conditions are in the where >>> clause -- to me at least. >>> >>> What makes it harder for me is that I'm generating the Cypher queries >>> dynamically, based on a tiny query language that the user puts together >>> using a web UI (originally through a lot of NOT|AND|OR dropdowns but now >>> with a rich editor embellished with auto-complete). So essentially the >>> query comes in the form of such-and-such-class-with-these-properties; it >>> gets compiled and then gets translated into Cypher after it passes >>> validation. >>> >>> It's definitely a lot easier to translate that user query into a Cypher >>> that actually allows new identifiers in the predicate; a lot more work to >>> do the translation in terms of union -- maybe even more than what I might >>> spend implementing the identifier in the predicates in Cypher. >>> >>> Does that make sense or would some examples with the more complex type >>> of queries help? >>> >>> Cheers, >>> Kai >>> >>> >>> On Tue, Oct 28, 2014 at 6:54 PM, Michael Hunger < >>> [email protected]> wrote: >>> >>>> 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 a topic in the >>>> Google Groups "Neo4j" group. >>>> To unsubscribe from this topic, visit >>>> https://groups.google.com/d/topic/neo4j/N5k06664XYI/unsubscribe. >>>> To unsubscribe from this group and all its topics, 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. >>> >> >> -- >> You received this message because you are subscribed to a topic in the >> Google Groups "Neo4j" group. >> To unsubscribe from this topic, visit >> https://groups.google.com/d/topic/neo4j/N5k06664XYI/unsubscribe. >> To unsubscribe from this group and all its topics, 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. > -- 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.
