Iterating through an array of ids to create relationships between them

Hello,

I need to create relationships between a number of entities, that are in an array.

Let's say i have 4 entities in an array, P1, P2,P3 and P4.

I need a query that creates (P1)-[r]->(P2) , (P1)-[r]->(P3) , (P1)-[r]->(P4), (P2)-[r]->(P3) , (P2)-[r]->(P4) , (P3)-[r]->(P4) .

I've been trying to search and use foreach but it doesn't seem to work this way

Could you provide more of your Cypher?
Are they in an array, collection, or list?

What is the problem your really trying to solve?
So many relationships isn't going to be very helpful for querying, and there is probably another way to organize your data that will be more useful. https://neo4j.com/developer/guide-data-modeling/

Assumptions:

  • Nodes are in a list.
  • Every node in list should have a relationship to every other node in list.
// WITH [P1, P2, P3, P4] as borg
WITH borg as borg1, borg as borg2
UNWIND borg1 as drone1
UNWIND borg2 as drone2
MERGE (drone1)-[]->(drone2)

Now you have your borg collective, where every drone has both an inbound, and an outbound, connection to every other drone.

1 Like

Jose, welcome to the community! Love the challenge. IMHO, it's easier to code problems like this in js, python or, in some cases, I've even used SQL - where you create the Cypher and then send that off to run or just copy/paste into the browser. I'm assuming you are wanting to create a "complete graph" but do NOT wish for self relationships - i.e., an adjacency matrix basically (1's in all pairs except for (0,0), (1,1), etc. I'm a graph nerd and Neo is a bit lenient for my blood in terms of direction of the relationship, so because it's iff'y doing (a)--(b), and I'm assuming you want the truly complete adjacency matrix, I would want to see a 1 value both for (a)<--(b) and (a)-->(b) explicitly.

I do wish Cypher had better loop and if/then/else constructs. Maybe someday :slight_smile:, but for now, in Cypher, this is a more challenging problem than it would be in say, Python. I'll piggy back of tony's great response but I'll remove that self-ref and make it copy/paste ready to test.

So, this will work:

CREATE (p1:P1),(p2:P2),(p3:P3),(p4:P4)
WITH [p1, p2, p3, p4] as borg
WITH borg as borg1, borg as borg2
UNWIND borg1 as drone1
UNWIND borg2 as drone2
WITH drone1, drone2 WHERE drone1 <> drone2
MERGE (drone1)-[:R]->(drone2)

...and will give you the view below. So, it's a bit "brute force" because it's O(n^2) and should be O((n(n-1))/2), which you'd get in a good Python implementation. Not a big deal for four nodes...but might be a concern for 4B :slight_smile:

HTH and thanks for giving me a fun break in my day :slight_smile:

1 Like

And if I misunderstood you and you only wanted a single direction, starting from your first node, use this tweak in the WHERE clause:

CREATE (p1:P1),(p2:P2),(p3:P3),(p4:P4)
WITH [p1, p2, p3, p4] as borg
WITH borg as borg1, borg as borg2
UNWIND borg1 as drone1
UNWIND borg2 as drone2
WITH drone1, drone2 WHERE drone1 <> drone2 and not (drone1)--(drone2)
MERGE (drone1)-[:R]->(drone2)

1 Like

Hi Jose, this will work:

// to create some P1, P2, P3, P4 nodes
WITH range(1, 4) AS r
FOREACH (x in r | CREATE (:Node {name: 'P' + x}))
// to create the relationships as you asked (and this can be extended to N nodes)
MATCH (p)
WITH p ORDER BY p.name
WITH collect(p) AS ps
FOREACH (i in range(0, size(ps)-2)
   | FOREACH (j in range(i+1, size(ps)-1)
   | FOREACH (p1 in [ps[i]]
   | FOREACH (p2 in [ps[j]]
   | MERGE (p1)-[:REL]->(p2)))))

Last 2 FOREACH are some required hacks, because MERGE/CREATE does not accept indexed list items in its syntax, just nodes.

Regards,
-C

1 Like

Thanks for the responses!
I think all of them help a lot understanding how to create this relationships. I'll try and implement them into my solution

Regards,
José Ferreira