cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Maintaining hierarchy constraints in nested tree

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.

5 REPLIES 5

MuddyBootsCode
Graph Steward

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.

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.

MuddyBootsCode
Graph Steward

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.

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.

MuddyBootsCode
Graph Steward

I attended a session today on https://neo4j.com/labs/neosemantics-rdf/ 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.

Nodes 2022
Nodes
NODES 2022, Neo4j Online Education Summit

All the sessions of the conference are now available online