I've run into the following issue with this Cypher query. The overall results are returned in an array of objects, as intended. However, the collect()
clause is giving me some trouble.
If user
has no myFriends
and no theirFriends
, an empty array should be returned. Otherwise, if myFriends
and/or theirFriends
has values, it should be a single array of objects of the combined friends, with the id property of the respective friend.
Query:
MATCH (user:User)
WHERE user.id IN ['1', '2', '3']
OPTIONAL MATCH (user)-[:HAS_FRIEND]->(myFriends:User)
OPTIONAL MATCH (user)<-[:HAS_FRIEND]-(theirFriends:User)
OPTIONAL MATCH (user)-[:HAS_TEACHER]->(myTeachers:User)
RETURN {
name: user.name,
friends: collect({id: myFriends.id}) + collect({id: theirFriends.id}),
teachers: collect({id: myTeachers.id})
}
Results in:
[
{
name: 'Joe',
friends: [{id: null}, {id: null}],
teachers: [{id: null}]
}, ...
]
Desired result:
[
{
name: 'Joe',
friends: [],
teachers: []
}, {
name: 'Jen',
friends: [{id: '4'}, {id: '6'}, {id: '7'}],
teachers: [{id: '8'}, {id: '9'}]
}
]
[UPDATED]
A really nice thing about your particular data model is: you can get all the myFriends
and theirFriends
elements with a single undirected relationship pattern: (user)-[:HAS_FRIEND]-(f)
.
For example:
MATCH (user:User)
WHERE user.id IN ['1', '2', '3']
OPTIONAL MATCH (user)-[:HAS_FRIEND]-(f:User)
OPTIONAL MATCH (user)-[:HAS_TEACHER]->(t:User)
RETURN {
name: user.name,
friends: COLLECT(DISTINCT f{.id}),
teachers: COLLECT(t{.id})
}
So, no list concatenation is needed. Also, the DISTINCT
option removes duplicate friends
elements.
By the way, this query also uses the neat map projections syntax as suggested by @P.S., which avoids null
values.