Search code examples
neo4jcypher

Cypher: group nodes by relation type


I have a data model that's something like:

(PersonA)-[:KNOWS]->(PersonB)
(PersonA)-[:KNOWS]->(PersonC)
(PersonA)-[:IS_FRIENDS_WITH]->(PersonD)
(PersonA)-[:LIKES]->(PersonE)

I'd like to write a query to return PersonA, with lists of related person grouped by the relation type. i.e.

{
     "id": "PersonA",
     "knows": [
         {"id": "PersonB"},
         {"id": "PersonC"}
     ],
     "is_friends_with": [
         {"id": "PersonD"}
     ],
     "likes": [
         {"id": "PersonE"}
     ]
}

Importantly, I can't hard code the relation types — they could, in theory, be anything!

Any idea? I've tried using something like apoc.map.groupMulti, but this only allows grouping on node properties, not the relationship type.


Solution

  • This should work:

    MATCH (a:Person)-[r]->(b)
    WHERE a.id = "PersonA"
    WITH a, TYPE(r) AS t, COLLECT({id: b.id}) AS bIds
    WITH a, COLLECT({t: t, bIds: bIds}) AS data
    RETURN REDUCE(s = {id: a.id}, d IN data | apoc.map.setEntry(s, d.t, d.bIds))
    

    The query assumes all person nodes have the Person label and a unique id property. The result looks likes this:

    {
      "id": "PersonA",
      "IS_FRIENDS_WITH": [
        {
          "id": "PersonD"
        }
      ],
      "KNOWS": [
        {
          "id": "PersonB"
        },
        {
          "id": "PersonC"
        }
      ],
      "LIKES": [
        {
          "id": "PersonE"
        }
      ]
    }