Say you have your data in the format (:ACTOR)->[:ACTED_IN]->(:MOVIE) and the edge [:ACTED_IN] had a property like { characterName: 'Neo' } . You would probably have your graphql schema looks like:
type Movie {
...
actors: [MovieRole]
}
type MovieRole {
node: Actor
characterName: String
}
type Actor {
...
}
The question then becomes, how do you represent this in our project? What I suggest is an additional property on the @relation directive, called through.
type Movie {
...
actors: [MovieRole] @relation(name: "ACTED_IN", direction:"OUT", through:"MovieRole")
}
The node property would represent the connected node, while any other properties would be assumed to be edge properties to be returned.
Looking for feedback on this idea. If anyone more familiar with the project/neo4j is interested in building it, I would be grateful - otherwise I might try.
Looks good, I wish I could help, but I have a hard time figuring out exactly how the library works (even after reading the code)
In a schema-first approach, MovieRole would be modeled as an object type in GraphQL with fields, which would then be mapped to a node with attributes in Neo4j.
In other words, given the limited expressiveness of the GraphQL language, one has no choice but to model edges as nodes if they are to have attributes.
I'm okay with this since I tend to want to model who made a relationship ("blame") and when (to a time tree), so I'd have elevated that edge to a node in time.
Plus, a MovieRole does have a meaning outside of the model: we may want to add an edge to a NewsReport node when casting news is announced online, for example.
That does make your queries more complex, or rather more wordy. It's also forcing a convention: all but the simplest of edges must be upgraded to nodes.
So, I'd prefer not to add the proposed "through" directive, even if that makes things more difficult when introducing GraphQL to an existing Neo4j database.
PS: Or you could use a "@cypher" directive (or resolver) to bring the related actors into the Movie query result. That would have greater expressiveness than your @relation/through proposal: you could also filter related nodes based on a node or edge attribute, etc.
Thanks for the feedback. I will try a cypher/resolver.
To clarify, this would be an optional property, so wouldn't force all edges that don't have properties to become graphql nodes.
@sys13 I'd be interested in how you worked around this with a resolver as I've a similar issue here (basically how do I pull some edge properties into my response)
@sys13 / @gaving I'm eager to know the solution. Please let me know if you were able to tackle it.
Here's how i've done it for now. *disclaimer: Im not saying its the correct way. Ive only just discovered GraphQL and Neo4j :).
A Party (Person) can be linked to multiple vehicles. The relationship property indicates the persons role in the vehicle. Driver, Passenger etc..
type Party {
email: String!
name: String
vehicles: [Vehicle] @cypher(statement: "MATCH (this)-[r:LINKED_TO_VEHICLE]->(v) RETURN v{.*, roleInVehicle: r.role}")
}
type Vehicle {
reg: String!
make: String
model: String
roleInVehicle: String
}
type MutationType {
addPartyToVehicle(email: String!, reg: String!, role: String!): String @cypher(statement: "MATCH (v:Vehicle { reg: $reg }), (p:Party { email: $email }) MERGE (v)<-[r:LINKED_TO_VEHICLE { role: $role }]-(p)")
}
schema {
mutation: MutationType
}
In v0.2.1 we added support for exposing relationship properties through the use of the @relation directive on a _type_ definition. For example:
type Movie {
title: String
year: Int
ratings: [Rated]
}
type User {
userId: ID
name: String
rated: [Rated]
}
type Rated @relation(name: "RATED") {
from: User
to: Movie
rating: Float
timestamp: Int
}
When queries are generated (through augmentSchema or makeAugmentedSchema) fields referencing a relationship type are replaced with a special payload type that contains the relationship properties and the type reference:
type _MovieRatings {
timestamp: Int
rating: Float
User: User
}
More information is available in the docs here.
Most helpful comment
@sys13 I'd be interested in how you worked around this with a resolver as I've a similar issue here (basically how do I pull some edge properties into my response)