Reputation: 13
I've got a Neo4j DB that contains Resource
nodes with several relationship nodes including Tag
, Address
, PhoneNumber
, etc.
The schema for Resource
is as follows:
Resource: {
name: str,
description: str,
legal_name: str,
organization_type: str,
}
The schema for Tag
is as follows:
Tag: {
tag: str,
}
I'm building a query that returns all Resource
nodes along with their relationship nodes where the Resource
node has a property that contains a specific string AND/OR related Tag
node(s) has(ve) a property that contains the same string.
Example cases to return:
Resource
node DOES have one or more property that contains the string "school" but all related Tag
nodes DO NOT have a tag
property containing the string "school": the Resource
node is returned along with all of its relationship nodesResource
node DOES NOT have any properties that contain the string "school" but has at least one related Tag
node that DOES have a tag
property containing the string "school": the Resource
node is returned along with all of its relationship nodesResource
node DOES have one or more property that contains the string "school" and has at least one related Tag
node that DOES have a tag
property containing the string "school": the Resource
node is returned along with all of its relationship nodesI'm currently using the below query and it works for the most part; however, for case 2 above no other relationship nodes of the originating Resource
node are returned in the result set. Ideally, we would ALWAYS get all relationship nodes of the Resource
node matching the above criteria. Any help would be greatly appreciated!
MATCH (n:Resource)-[]->(m)
WHERE n.name CONTAINS 'school'
OR n.description CONTAINS 'school'
OR n.legal_name CONTAINS 'school'
OR n.organization_type CONTAINS 'school'
OR m.tag CONTAINS 'school'
RETURN n, collect(m);
Upvotes: 0
Views: 82
Reputation: 1461
The Tags
look a lot like labels. Their one property, tag
, could just as easily be the label identifier. With the tags as labels, the predicates can be simplified like so:
WITH ['name', 'description', 'legal', 'organization_type'] AS props
MATCH (n:Resource)-->(m)
WHERE n:School OR any(prop IN props WHERE m[prop] CONTAINS 'school')
RETURN n, collect(m);
Upvotes: 0
Reputation: 30417
You could try a query like this:
MATCH (n:Resource)
WHERE EXISTS {
MATCH (n)-[*0..1]->(x)
WHERE (x:Resource OR x:Tag)
AND any(prop IN ['name', 'description', 'legal_name', 'organization_type', 'tag'] WHERE x[prop] CONTAINS 'school')
}
WITH n, [(n)-[]->(m) | m] as resources
RETURN n, resources;
This uses an EXISTS {} subquery to say that you're looking for a node (that could be the same node, or could be a connected node) that is a :Resource or :Tag node that has any of the given properties with the property value contains 'school'.
For the resulting nodes that pass that filter, THEN you can match out to and collect the connected nodes (though in this case I'm using a pattern comprehension to do so, which will be more efficient).
EDIT: Fixed up the grouping of the AND and OR operators, that should ensure the any() list predicate must always be considered.
Upvotes: 0