You are very welcome.
In regards to question 'A', the variable length pattern will result in many paths that match. You can see this using the same data as above and removing the conditions. The results below are when I specify the 'x' node as the 'apartment.' The result is six paths that match the pattern. You see that many are paths that are a partial path of the whole path,. In order to get the entire path, we can add constrains to the pattern to filter out the partial paths. One constraint would be that the node bound to the 'begin' variable be a starting node of the path, i.e. that it does not have an incoming IS_IN relationship. Only the 'chair' node meets this criteria, so adding this will eliminate all the partial paths in the results below that do not start with the 'chair' node.
The other criteria is for the node bound to the 'end' variable to be an end node, i.e. it does not have an outgoing relationship to another Thing node. Only the building node meets this condition. Adding this will filter out from the above results any path that does not end on the 'building' node. The only path matching path conditions is the last path in the result, which is the only one that represents the entire path.
The not exists ((end)-[:IS_IN]->(:Thing))
condition states that there can't exist an outgoing IS_IN relationship from the 'end' node to any 'Thing' node.
The not exists (()-[:IS_IN]->(begin:Thing))
condition states that there can't exist an incoming IS_IN relationship to the 'begin' node from any node.
I notice the two conditions are written a little differntly, so use this version instead:
match p = (begin:Thing)-[:IS_IN*0..]->(x:Thing)-[:IS_IN*0..]->(end: Thing)
where x.name= 'apt 17'
and not exists ((end)-[:IS_IN]->(:Thing))
and not exists ((:Thing)-[:IS_IN]->(begin))
return nodes(p) as nodes
In regards to question B, when you specify "*' it represents a min length of one and an unbounded max length. I used "*0.." to specify a min length of zero. This allows the node bound to the 'x' node to be the 'begin' node or the 'end' node if necessary. For instance, the two queries will work when using the zero min length condition:
match p = (begin:Thing)-[:IS_IN*0..]->(x: Thing)-[:IS_IN*0..]->(end: Thing)
where x.type = 'chair'
and not exists ((end)-[:IS_IN]->(: Thing))
and not exists ((: Thing)-[:IS_IN]->(begin))
return nodes(p) as nodes
or
match p = (begin:Thing)-[:IS_IN*0..]->(x: Thing)-[:IS_IN*0..]->(end: Thing)
where x.type = 'building'
and not exists ((end)-[:IS_IN]->(: Thing))
and not exists ((: Thing)-[:IS_IN]->(begin))
return nodes(p) as nodes
If you use a min length of one, then neither of the two queries would return a result, as the 'x' node has to be a minimum of one hope away from both the 'chair' and 'building' nodes.