Reputation: 22592
I'm currently early in my learning of Neo4J and Cypher, so would appreciate any advice on this I can get!
What I'm looking to-do, is fetch a list of "Items". Those items come from "Lists", either directly "OWNED" by me, or "OWNED" by a "Group" I am a "MEMBER":
Thus far, I have (For fetching items from Lists I directly own):
MATCH (owner:User {identifier: "b3b57bc7-f7d2-4915-89b7-b111510d66b0"})-[OWNS]->(list:List)-[HAS]->(item:Item)
RETURN {identifier: item.identifier, title: item.title, list: list.identifier}
How would I compliment this with the lists of groups I am a member?
I'm hoping to get back (To satisfy GraphQL) the following format:
[
{
identifier: "item-1-identifier,
title: "My Item",
list: "list-1-identifier"
},
{
identifier: "item-2-identifier,
title: "My Item on another list",
list: "list-2-identifier"
}
]
Thanks!
Upvotes: 0
Views: 93
Reputation: 16375
I created a small dataset to reproduce your scenario. The script for this dataset can be found here.
Alternatively to InverseFalcon solution (and as mentioned by InverseFalcon) you can do this using COLLECT and UNWIND as follow:
// First match all items from lists owned by the user
MATCH (user:User {identifier:"b3b57bc7-f7d2-4915-89b7-b111510d66b0"})-[:OWNS]->(list:List)-[:HAS]->(item:Item)
// Pass the user and all information about items and list to the next context
WITH user, COLLECT({identifier: item.identifier, title: item.title, list: list.identifier}) AS userListItems
// Match all items from lists owned by groups that the user is a member
MATCH (user)-[:MEMBER]->(group:Group)-[:OWNS]->(list:List)-[:HAS]->(item:Item)
// Collect the result and add the previous result
WITH COLLECT({identifier: item.identifier, title: item.title, list: list.identifier}) + userListItems as allItems
// anwind all
UNWIND allItems as unwinded
// return in the desired format
RETURN {identifier: unwinded.identifier, title: unwinded.title, list: unwinded.identifier}
The result based on the dataset:
╒══════════════════════════════╕
│"{identifier: unwinded.identif│
│ier, title: unwinded.title, li│
│st: unwinded.identifier}" │
╞══════════════════════════════╡
│{"identifier":"item3","title":│
│"Item 3","list":"item3"} │
├──────────────────────────────┤
│{"identifier":"item1","title":│
│"Item 1","list":"item1"} │
├──────────────────────────────┤
│{"identifier":"item2","title":│
│"Item 2","list":"item2"} │
├──────────────────────────────┤
│{"identifier":"item6","title":│
│"Item 6","list":"item6"} │
├──────────────────────────────┤
│{"identifier":"item4","title":│
│"Item 4","list":"item4"} │
├──────────────────────────────┤
│{"identifier":"item5","title":│
│"Item 5","list":"item5"} │
├──────────────────────────────┤
│{"identifier":"item9","title":│
│"Item 9","list":"item9"} │
├──────────────────────────────┤
│{"identifier":"item7","title":│
│"Item 7","list":"item7"} │
├──────────────────────────────┤
│{"identifier":"item8","title":│
│"Item 8","list":"item8"} │
└──────────────────────────────┘
According with PROFILE this query hits the database 62 times. Very similar to the very elegant solution provided by InverseFalcon that hits the database 61 times.
Upvotes: 1
Reputation: 30407
To get both your lists and your group lists into a single column, you can either change the relationships traversed to match to either path, or you'll need to either use UNION or COLLECT both sets of items and combine the collections, then UNWIND back to rows.
Here's an example of changing the relationships traversed, which should be easiest.
MATCH (owner:User {identifier: "b3b57bc7-f7d2-4915-89b7-b111510d66b0"})-[:MEMBER*0..1]->()-[:OWNS]->(list:List)-[:HAS]->(item:Item)
RETURN {identifier: item.identifier, title: item.title, list: list.identifier}
The lower bound of 0
for the :MEMBER
relationship means it's optional, which will allow the pattern to match to both the user's lists and lists of groups for which the user is a member.
Upvotes: 3