返回 Neo4J 中每个 session 的任务(列表列表)

Returning tasks for each session in Neo4J (list of lists)

我将 Neo4J 用于我正在构建的导师平台,但我被以下问题难住了:

给定以下节点和属性:

Mentor{ login, ... }
Mentee{ login, ... }
Session{ notes, ... }
Task{ complete, name }

以及以下协会:

// each session has 1 mentor and 1 mentee
(Mentor)<-[:HAS]-(Session)-[:HAS]->(Mentee)

// each task is FOR one person (a Mentor or Mentee)
// each task is FROM one Session
(Session)<-[:FROM]-(Task)-[:FOR]->(Mentor or Mentee)

查询此数据以生成以下形状的 API 响应的最佳方法是什么?同样,这是对数据建模的合理方法吗?也许 coalesce?

{
  mentor: { login: '...', /* ... */ },
  mentee: { login: '...', /* ... */ },
  sessions: [
    {
      notes,
      /* ... */
      mentorTasks: [{ id, name, complete }],
      menteeTasks: [{ id, name, complete }]
  ]

我第一次尝试:

MATCH (mentor:Mentor{ github: "mentorlogin" })
MATCH (session:Session)-[:HAS]->(mentee:Mentee{ github: "menteelogin" })
OPTIONAL MATCH (mentor)<-[:FOR]-(mentorTask:Task)-[:FROM]->(session)
OPTIONAL MATCH (mentee)<-[:FOR]-(menteeTask:Task)-[:FROM]->(session)

RETURN
  mentor,
  mentee,
  session,
  COLLECT(DISTINCT mentorTask) as mentorTasks,
  COLLECT(DISTINCT menteeTask) as menteeTasks

ORDER BY session.date DESC

但这很糟糕 - 导师和受训者数据被 returned 多次,如果受训者没有会话,它就完全消失了。

这似乎更合适,但我不确定如何折叠任务:

MATCH (mentor:Mentor{ github: "mentorlogin" })
MATCH (mentee:Mentee{ github: "menteelogin })
OPTIONAL MATCH (session:Session)-[:HAS]->(mentee)
OPTIONAL MATCH (mentor)<-[:FOR]-(mentorTask:Task)-[:FROM]->(session)
OPTIONAL MATCH (mentee)<-[:FOR]-(menteeTask:Task)-[:FROM]->(session)

RETURN
  mentor,
  mentee,
  COLLECT(DISTINCT session) as sessions

编辑:工作!感谢 Graphileon 的及时回复。我做了一些修改:

MATCH (mentor:Mentor{ github: $mentorGithub })
MATCH (mentee:Mentee{ github: $menteeGithub })

RETURN DISTINCT {
  mentor: mentor{ .*, id: toString(id(mentor)) },
  mentee: mentee{ .*, id: toString(id(mentee)) },
  sessions: apoc.coll.sortMaps([(mentor:Mentor)<-[:HAS]-(session:Session)-[:HAS]->(mentee:Mentee) |
    session{
      .*,
      id: toString(id(session)),
      mentorTasks: [
        (session)<-[:FROM]-(task:Task)-[:FOR]->(mentor) |
        task{ .*, id: toString(id(task)) }
      ],
      menteeTasks: [
        (session)<-[:FROM]-(task:Task)-[:FOR]->(mentee) |
        task{ .*, id: toString(id(task)) }
      ]
    }
  ], "date")
} AS result

假设您拥有这些数据:

你可以按照这些思路做一些事情,嵌套 pattern comprehensions

MATCH (mentor:Mentor)<-[:HAS]-(:Session)-[:HAS]->(mentee:Mentee)
RETURN DISTINCT {
        mentor: {id:id(mentor), name: mentor.name},
        mentee: {id:id(mentee), name: mentee.name},
        sessions: [(mentor:Mentor)<-[:HAS]-(session:Session)-[:HAS]->(mentee:Mentee) | 
                      { id: id(session),
                        name: session.name,
                        mentorTasks: [(session)<-[:FROM]-(task:Task)-[:FOR]->(mentor) |
                                        {id:id(task), name: task.name}
                                     ],
                        menteeTasks: [(session)<-[:FROM]-(task:Task)-[:FOR]->(mentee) |
                                        {id:id(task), name: task.name}
                                     ]                     
                      }  
                  ]
       } AS myResult

回归

{
  "mentor": {
    "name": "Mentor Jill",
    "id": 211
  },
  "sessions": [
    {
      "menteeTasks": [
        {
          "id": 223,
          "name": "Task D"
        },
        {
          "id": 220,
          "name": "Task C"
        },
        {
          "id": 219,
          "name": "Task B"
        }
      ],
      "name": "Session 1",
      "id": 208,
      "mentorTasks": [
        {
          "id": 213,
          "name": "Task A"
        }
      ]
    }
  ],
  "mentee": {
    "name": "Mentee Joe",
    "id": 212
  }
}

请注意,使用模式理解,您可以避免 OPTIONAL 匹配。如果模式理解没有找到任何东西,它 returns []