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.

Reply via email to