Best way to find node neighborhood?

Hello,
I'm starting with Neo4J. For a given node I want to list Outgoing & Incoming relationships.
I do this :

// List Outgoing & Incoming relations for a node
// Outgoing
MATCH (s)-[r]->(t)
WHERE s.name = 'f4b1'
RETURN t.name , 'Out' as `relations`
UNION ALL
// Incoming
MATCH (t)<-[r]-(s)
WHERE t.name = 'f4b1'
RETURN t.name , 'In' as `relations`

Is this the best way?

Example based on the movies dataset without the need for a JOIN:

MATCH (p:Person {name: "Jessica Thompson"})-[r]-(o)
RETURN p.name
              , p = endNode(r) as isIncoming
              , type(r) as relationType
              , coalesce(o.name, o.title) as other

Thank you so much for your help.

Do you think is it possible to have an inRel array with the inComing node IDs and an outRel array with the outgoing node IDs`?

You can use pattern comprehension for this:

MATCH (s) // you should really use labels here, and create an index to support fast lookup by property
WHERE s.name = 'f4b1'
RETURN [(s)<--(t) | t.name] as In, [(s)-->(t) | t.name] as Out
2 Likes

If you have multiple relationships, you can use DISTINCT.

MATCH (t_in)-->(s)-->(t_out)
WHERE s.name = 'f4b1'
RETURN collect(DISTINCT(t_in.name)) as In,
       collect(DISTINCT(t_out.name)) as Out;

This is the cypher for creation.

CREATE (n:S{name:'f4b1'}),
       (in1:In{name:'data_in_1'})-[:REL]->(n)-[:REL]->(:Out{name:'data_out_1'}),
       (:In{name:'data_in_2'})-[:REL]->(n)-[:REL]->(:Out{name:'data_out_2'}),
       (:In{name:'data_in_3'})-[:REL]->(n)-[:REL]->(:Out{name:'data_out_3'}),
       (:In{name:'data_in_4'})-[:REL]->(n),
       (n)-[:REL]->(out5:Out{name:'data_out_5'}),
       (n)-[:REL]->(:Out{name:'data_out_6'}),
       (in1)-[:REL]->(n),
       (n)-[:REL2]->(out5);

'data_in_1' and 'data_out_5' are displayed only one each.

in_out_result

Thank you all so much. Very informative.

@andrew.bowman:
About your comment: you should really use labels here, and create an index to support fast lookup by property I do this :

MATCH (s:User)
WHERE s.name = 'f4b1'
RETURN [(s)<--(t) | t.name] as In, [(s)-->(t) | t.name] as Out

name is unique per user, I just create an constraint like this:
CREATE CONSTRAINT ON (n:User) ASSERT n.name IS UNIQUE

If name isn't unique per user, J just create a plain index instead:
CREATE INDEX ON :User(name)

Is that correct?

Yep, looks good.

You can always confirm if an index is being used or not by running an EXPLAIN of the query, it will show you how the starting nodes are looked up.