Neo4j and unidirectional relationships

I am new to neo4j

. I just read some information about this tool, installed it on Ubuntu and made a bunch of requests. And at this point I have to admit that I really like it. However, there is something (very simple and intuitive I think) that I don't know how to implement. So, I created three such nodes:

CREATE (n:Object {id:1}) RETURN n
CREATE (n:Object {id:2}) RETURN n
CREATE (n:Object {id:3}) RETURN n

      

And I created a hierarchical relationship between them:

MATCH (a:Object {id:1}), (b:Object {id:2}) CREATE (a)-[:PARENT]->(b)
MATCH (a:Object {id:2}), (b:Object {id:3}) CREATE (a)-[:PARENT]->(b)

      

So, I think this simple hierarchy should look like this:

(id:1) 
      -> (id:2)
               -> (id:3)

      

Now I want to get the path from any node. For example, if I want to have a path from node (id: 2), I will get (id: 2) → (id: 3). And if I want to get the path from node (id: 1), I get (id: 1) -> (id: 2) -> (id: 3). I tried this query:

MATCH (n:Object {id:2})-[*]-(children) return n, children

      

which should return the path (id: 2) -> (id: 3), but unexpectedly (just for me) it returns (id: 1) -> (id: 2) -> (id: 3). So what am I doing wrong and what is the correct query to use?

+3


source to share


2 answers


All relationships in neo4j are directed. When you speak (n)-[:foo]->(m)

, this relationship only goes one way: from n

to m

.

Now the difficulty is that you can navigate both paths. It doesn't make the relationship bi-directional, it never will - it means you can look at it in any direction.

When you write this request:, (n:Object {id:2})-[*]-(children)

you have not put an arrow on this link, so it children

can refer to something either downstream or upstream of node.



In other words, the expression (n)-[:test]-(m)

matches both (n)<-[:test]-(m)

and (n)-[:test]->(m)

.

So it children

can refer to object ID 1 or object ID 2.

+2


source


Return of children only

To answer your question,

Your request

MATCH (n:Object {id:2})-[*]-(children) return n, children

      

matches not only the FROM (n {id:2})

TO relationship of its children, but also the TO (n {id:2})

FROM relationship of its parents.

You need to additionally indicate the direction you want. This returns the expected results:

MATCH (n:Object {id:2})-[*]->(children) return n, children

      




Example problems

I would like to respond to your comment about unidirectional versus bidirectional relationships, but first solve a couple of problems with an example.

Using the correct labels

Repeat your example:

(:Object {id:1})-[:PARENT]->(:Object {id:2})-[:PARENT]->(:Object {id:3})

      

It makes no sense to use such labels as :Object

, :Node

, :Thing

. If you really don't care, don't use the shortcut at all!

In this case, it looks like we are talking about humans, although it could easily be motherboards and daughterboards or something else!

Let's use "People" instead of "Objects":

(:Person {id:1})-[:PARENT]->(:Person {id:2})-[:PARENT]->(:Person {id:3})

      

ID in Neo4j

Neo4j stores its own IDs for each node and relationship. You can get these IDs with id(nodeOrRelationship)

and access by ID with suggestion WHERE

or by specifying them as a starting point for your match. START n=node(2) MATCH (n)-[*]-(children) return n, children

is equivalent to the original query MATCH (n:Object {id:2})-[*]-(children) return n, children

.

Let's keep something useful about nodes instead of identifiers, like names:

(:Person {name:'Bob'})-[:PARENT]->(:Person {name:'Mary'})-[:PARENT]->(:Person {name:'Tom'})

      

Ambiguity of relationship

Finally, let's get the relationship out of alignment. Does it mean PARENT

"parent" or "has this parent"? It may be clear to you what you mean, but someone unfamiliar with your system might have the opposite interpretation.

I think you meant "is the parent", so let's make it clear:

(:Person {name:'Bob'})-[:PARENT_OF]->(:Person {name:'Mary'})-[:PARENT_OF]->(:Person {name:'Tom'})

      




More information on unidirectional and bidirectional communications in Neo4j

Now that we've covered a few basic issues with the example, let's turn to the directionality of relationships in Neo4j and charts in general.

There are several ways that we could express the relationship in this example. Let's take a look at a few.

Indirect / bi-directional relationship

Let's abstract the parenting relationship we used above for discussion purposes:

(bob)-[:KIN]-(mary)-[:KIN]-(tom)

      

Here the relationship KIN

indicates that they are related, but we don't know exactly who the parent is. Is Tom Mary's child or vice versa?

Note that I have not used any arrows. In the above plot pseudocode, the relationship KIN

is a bidirectional or undirected relationship.

Relationships in Neo4j, however, are always directed. If attitude KIN

was really how you wanted to keep track of things, then you would create a directional connection, but always ignore direction in your requests MATCH

, for example. MATCH (a)-[:KIN]-(b)

rather than MATCH (a)-[:KIN]->(b)

.

But is an attitude really the KIN

best way to store this information? We can make this more specific. Let's go back to the relationships PARENT_OF

we used earlier.

Directional / unidirectional ratio

Let's go back to the example. We know that Bob is the parent of Mary, who is Tom's parent:

(bob)-[:PARENT_OF]->(mary)-[:PARENT_OF]->(tom)

      

Obviously, the consequence of this is:

(bob)<-[:CHILD_OF]-(mary)<-[:CHILD_OF]-(tom)

      

Or, equivalently:

(tom)-[:CHILD_OF]->(mary)-[:CHILD_OF]->(bob)

      

So, whether we should continue and build relationships PARENT_OF

and CHILD_OF

between our (bob), (mary) and (tom) sites?

The answer is no. We can choose one of these relationships, depending on which is the best model of the idea, and still be able to search in both directions.

Using just a relation :PARENT_OF

, we can do

MATCH (mary {name:'Mary'})-[:PARENT_OF]->(children) RETURN children

      

to find children, or

MATCH (mary {name:'Mary'})<-[:PARENT_OF]-(parents) RETURN parents

      

to find parents using (mary) as a starting point every time.




For more information see this fantastic article from GraphAware

+1


source







All Articles