I'm looking for strategies to handle parts of a tree where I need to maintain certain contstraints as you go two levels deep. Consider this GraphQL example:
{
text{
body
names{
name
startIndex
endIndex
people {
title
_id
}
}
}
}
A text includes strings which are a person's name. That person may have multiple names, so there is a separate node representing that unique individual. But, if the name
node in the above example is shared by more than one person, it will list multiple people. There are similar examples for other entity types.
What I want to do is make sure that the person returned is constrained by its relationship to the text node. We do have this relationship in our database, so it is possible to query all of the following:
(:Text)-[:MENTIONS]->(:Person)
(:Text)-[:MENTIONS]->(:Name)
(:Person)-[:NAMED]->(:Name)
How can we construct a GraphQL schema or query such that we can get the person mentioned in that particular text? Are we stuck with @cypher
directives handling very specific tree hierarchies, or is there a way to make it more flexible?
The best way I can think of to handle it is with GraphQL queries that are only one level deep, then relate the results on the client side. For example, we might do this:
{
text{
body
names{
_id
entities{
_id
}
}
entities {
_id
names {
_id
}
}
}
}
From there, we'd need JavaSCript functions to match or filter names and entities by _id
. That seems really ugly.
Soulliberty, welcome to the community. It seems like what you're after is going to be using the ability in your GraphQL schema to either create an individual Cypher query or add a @cyper directive query on your type. But off the top of my head it looks like you could have something like:
type text {
entities: [Person] @cypher (
statement: "MATCH (this)-[:MENTIONS || :NAMED]->(p) return p"
}
You can then filter the results on the front end whoever you like. Just a rough idea.
1 Like
I think we can do cypher statements like this for specific cases, and maybe that's our only answer. Our [Name] nodes have a different type and properties than the [Person] nodes which is why this is more complicated.
The other thing to do is just write a fully custom Cypher query to handle it and feed your variables. When I've been faced with something that gets more complex in the past that's what I've ended up doing.
1 Like
Another idea we've had is to ensure that certain nodes remain unique to certain relationship pairs. Let's say a chapter mentions "Mary." Instead of having one Name
Node for "Mary," we would create unique name nodes for every individual with that name. It may look like this:
names: [
{
name: "Mary",
id: 1,
person: {
title: "Mary Sue"
},
texts: [some_text_list]
},
{
name: "Mary",
id: 2,
person: {
title: "Mary Jo"
},
texts: [some_other_list]
},
]
This way, we maintain a one-to-one relationship that will always carry through the tree. It makes querying unique names a little tougher, but that's acceptable given our use case.
I attended a session today on neosemantics (n10s): Neo4j RDF & Semantics toolkit - Neo4j Labs Neo semantics allows you to do quite a bit creating constraints on your graph that's not available out of the box with Neo4j alone. It might be worth you time to look at.