cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! Site migration is underway. Phase 2: migrate recent content

Dynamically collapsing parts of path to reduce nodes/rels

Niels
Node

Hi there,

I am trying to (dynamically) collapse/reduce certain parts of a graph to reduce the amount of nodes/rels in the output to the user.

This is a small sample of my dataset:

CREATE (c1:Connection {name: 'C1'})
CREATE (c2:Connection {name: 'C2'})
CREATE (c3:Connection {name: 'C3'})

CREATE (f1:File {name: 'F1'})
CREATE (f2:File {name: 'F2'})
CREATE (f3:File {name: 'F3'})
CREATE (f4:File {name: 'F4'})
CREATE (f5:File {name: 'F5'})
CREATE (f6:File {name: 'F6'})

CREATE (m1:Monitor {name: 'M1'})


MERGE (c1)-[:RECEIVES]->(f1)
MERGE (c2)-[:RECEIVES]->(f2)
MERGE (c2)-[:RECEIVES]->(f3)
MERGE (f1)<-[:MONITORS]-(m1)
MERGE (f2)<-[:MONITORS]-(m1)
MERGE (f3)<-[:MONITORS]-(m1)
MERGE (f4)<-[:MONITORS]-(m1)
MERGE (f5)<-[:MONITORS]-(m1)
MERGE (f6)<-[:MONITORS]-(m1)
MERGE (f4)-[:SENDS]->(c3)
MERGE (f5)-[:SENDS]->(c3)
MERGE (f6)-[:SENDS]->(c3)

 Which looks like this:

Niels_0-1668457015910.png

And what I want is something like this:

Niels_1-1668457056163.png

Where the aggregated relations would contain the number of relations it aggregated (so C1->M1 = 1, C2->M1 = 2, M1->C3 = 3).

I have tried using both ` apoc.create.vRelationship`  and ` apoc.nodes.collapse`  but I am unable to obtain my desired result. I can always resort to computing the aggregated relations and store them in the DB, but I would really like to avoid that as it requires me to rerun that computation each time new data is inserted into the DB.

Would anyone be able to help me on this? Let me know if I should provide more information.

1 ACCEPTED SOLUTION

My mistake.  I forgot to import 'm' into the call subquery, so each match was not constrained to 'M1'.

Try this:

match(m:Monitor{name:"M1"})
call{
    with m
    match(m)--()-[:RECEIVES]-(c:Connection)
    with m, c, count(*) as cnt
    CALL apoc.create.vRelationship(c,'RECEIVES_AGG',{number:cnt},m) YIELD rel
    return c, rel
    union
    with m
    match(m)--()-[:SENDS]-(c:Connection)
    with m, c, count(*) as cnt
    CALL apoc.create.vRelationship(m,'SENDS_AGG',{number:cnt},c) YIELD rel
    return c, rel
}
return *

View solution in original post

4 REPLIES 4

glilienfield
Ninja
Ninja

Try this:

match(m:Monitor{name:"M1"})
call{
    match(m)--()-[:RECEIVES]-(c:Connection)
    with m, c, count(*) as cnt
    CALL apoc.create.vRelationship(c,'RECEIVES_AGG',{number:cnt},m) YIELD rel
    return c, rel
    union
    match(m)--()-[:SENDS]-(c:Connection)
    with m, c, count(*) as cnt
    CALL apoc.create.vRelationship(m,'SENDS_AGG',{number:cnt},c) YIELD rel
    return c, rel
}
return *

Screen Shot 2022-11-14 at 4.24.31 PM.png 

Screen Shot 2022-11-14 at 4.26.31 PM.png

Hi glilienfield,

Thank you for the quick response!

I tried your query and I think I'm almost there. In my actual dataset, there are numerous other nodes (with similar structures/flow as this example).

If you add the following data (an another completely unrelated subgraph):

MERGE (c4:Connection {name: 'C4'})-[:RECEIVES]->(f7:File {name: 'F7'})<-[:MONITORS]-(m2:Monitor {name: 'M2'})-[:MONITORS]->(f8:File {name: 'F8'})-[:SENDS]->(c5:Connection {name: 'C5'})

  You'll see your query returning this:

Niels_0-1668464970042.png

I don't get why this happens; we only match connections that are connected to M1 right? How are Connection nodes from another Monitor/subgraph then returned as well?

My mistake.  I forgot to import 'm' into the call subquery, so each match was not constrained to 'M1'.

Try this:

match(m:Monitor{name:"M1"})
call{
    with m
    match(m)--()-[:RECEIVES]-(c:Connection)
    with m, c, count(*) as cnt
    CALL apoc.create.vRelationship(c,'RECEIVES_AGG',{number:cnt},m) YIELD rel
    return c, rel
    union
    with m
    match(m)--()-[:SENDS]-(c:Connection)
    with m, c, count(*) as cnt
    CALL apoc.create.vRelationship(m,'SENDS_AGG',{number:cnt},c) YIELD rel
    return c, rel
}
return *

Yes that works, thanks!