Table of Contents
- Schema
- Queries
- Top Level Query
- Query Single Object
- Basic Query with Parameter
- Paging
- Query Single Relation
- Query Single Object and Array of Object Relations
- Relationship Expansion
- Projection with sub-paging
- Subquery Cypher Directive
- Subquery Cypher Directive Paging
- Handle Cypher Directive on Query Type
- Handle Cypher directive on Mutation type
- Query using Inline Fragment
- Deeply nested object query
- Should merge an actor by the userId
- Should auto generate
addrelationship mutations for arrays - Should auto generate
deleterelationship mutations for arrays - Should auto generate
addrelationship mutations - Should auto generate
deleterelationship mutations - Should auto generate
addrecursive relationship mutations for arrays
- Order By
- Neo4j Data Types queryies
type Movie {
_id: Int
movieId: ID!
title: String
year: Int
released: Int # was DateTime
plot: String
poster: String
imdbRating: Float
genres: [Genre] @relation(name: "IN_GENRE", direction: OUT)
similar(first: Int = 3, offset: Int = 0): [Movie] @cypher(statement: "MATCH (this)--(:Genre)--(o:Movie) RETURN o")
mostSimilar: Movie @cypher(statement: "RETURN this")
degree: Int @cypher(statement: "RETURN SIZE((this)--())")
actors(first: Int = 3, offset: Int = 0, name: String): [Actor] @relation(name: "ACTED_IN", direction:IN)
avgStars: Float
filmedIn: State @relation(name: "FILMED_IN", direction: OUT)
scaleRating(scale: Int = 3): Float @cypher(statement: "RETURN $scale * this.imdbRating")
scaleRatingFloat(scale: Float = 1.5): Float @cypher(statement: "RETURN $scale * this.imdbRating")
actorMovies: [Movie] @cypher(statement: """
MATCH (this)-[:ACTED_IN*2]-(other:Movie)
RETURN other
""")
publishedBy: Publisher @relation(name: "PUBLISHED_BY", direction: OUT)
ratings: [Rated] @relation(name:"RATED")
}
type Publisher {
name: ID!
}
type Genre {
_id: String!
name: ID!
movies(first: Int = 3, offset: Int = 0): [Movie] @relation(name: "IN_GENRE", direction: IN)
highestRatedMovie: Movie @cypher(statement: "MATCH (m:Movie)-[:IN_GENRE]->(this) RETURN m ORDER BY m.imdbRating DESC LIMIT 1")
}
type State {
_id: ID!
name: String
}
interface Person {
userId: ID!
name: String
}
type Actor implements Person
{
userId: ID!
name: String
movies: [Movie] @relation(name: "ACTED_IN", direction:OUT)
born: _Neo4jDateTime
}
type User implements Person
{
userId: ID!
name: String
rated(rating: Int): [Rated]
friends(since: Int): [FriendOf]
knows: [User] @relation(name: "KNOWS", direction:OUT)
born: _Neo4jDateTime
}
type FriendOf {
from: User
since: Int
to: User
}
type Rated @relation(name:"RATED") {
_id: ID!
from: User
rating: Int
to: Movie
}
enum BookGenre {
Mystery,
Science,
Math
}
type Book {
genre: BookGenre
}
enum _MovieOrdering {
title_desc,
title_asc
}
enum _GenreOrdering {
name_desc,
name_asc
}
type Query {
Movie(_id: String, movieId: ID, title: String, year: Int, plot: String, poster: String, imdbRating: Float, first: Int, offset: Int, orderBy: _MovieOrdering): [Movie]
MoviesByYear(year: Int): [Movie]
MovieById(movieId: ID!): Movie
MovieBy_Id(_id: String!): Movie
GenresBySubstring(substring: String): [Genre] @cypher(statement: "MATCH (g:Genre) WHERE toLower(g.name) CONTAINS toLower($substring) RETURN g")
Books: [Book]
User: [User]
}
type Mutation {
createGenre(name:String): Genre @cypher(statement:"CREATE (g:Genre) SET g.name = name RETURN g")
changePerson(name: String): Person
}
# scalar DateTimeGraphQL-Query
query {
Movie {
movieId
}
}Cypher Params
{}Cypher
MATCH (movie:Movie)
RETURN movie { .movieId } AS movieGraphQL-Query
{
MovieById(movieId: "18") {
title
}
}Cypher Params
{
"movieByIdMovieId": "18"
}Cypher
MATCH (movieById:Movie)
WHERE movieById.movieId = $movieByIdMovieId
RETURN movieById { .title } AS movieByIdGraphQL-Query
{ Movie(title: "River Runs Through It, A") { title } }Cypher Params
{
"movieTitle": "River Runs Through It, A"
}Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie { .title } AS movieGraphQL-Query
{
Movie(title: "River Runs Through It, A", first: 1, offset: 1) {
title
year
}
}Cypher Params
{
"movieTitle": "River Runs Through It, A",
"movieOffset": 1,
"movieFirst": 1
}Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie { .title, .year } AS movie
SKIP $movieOffset LIMIT $movieFirstGraphQL-Query
{
MovieById(movieId: "3100") {
title
filmedIn {
name
}
}
}Cypher Params
{
"movieByIdMovieId": "3100"
}Cypher
MATCH (movieById:Movie)
WHERE movieById.movieId = $movieByIdMovieId
RETURN movieById {
.title,
filmedIn:[(movieById)-[:FILMED_IN]->(movieByIdFilmedIn:State) | movieByIdFilmedIn { .name }][0]
} AS movieByIdGraphQL-Query
{
MovieById(movieId: "3100") {
title
actors {
name
}
filmedIn{
name
}
}
}Cypher Params
{
"movieByIdMovieId": "3100"
}Cypher
MATCH (movieById:Movie)
WHERE movieById.movieId = $movieByIdMovieId
RETURN movieById {
.title,
actors:[(movieById)<-[:ACTED_IN]-(movieByIdActors:Actor) | movieByIdActors { .name }],
filmedIn:[(movieById)-[:FILMED_IN]->(movieByIdFilmedIn:State) | movieByIdFilmedIn { .name }][0]
} AS movieByIdGraphQL-Query
{
Movie(title: "River Runs Through It, A") {
title
actors {
name
}
}
}Cypher Params
{
"movieTitle": "River Runs Through It, A"
}Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie {
.title,
actors:[(movie)<-[:ACTED_IN]-(movieActors:Actor) | movieActors { .name }]
} AS movieGraphQL-Query
{
Movie(title: "River Runs Through It, A") {
title
actors(first:3) {
name
}
}
}Cypher Params
{
"movieTitle": "River Runs Through It, A",
"movieActorsFirst": 3
}Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie {
.title,
actors:[(movie)<-[:ACTED_IN]-(movieActors:Actor) | movieActors { .name }][0..$movieActorsFirst]
} AS movieGraphQL-Query
{
Movie {
title
similar {
title
}
}
}Cypher Params
{
"movieFirst": 3,
"movieOffset": 0
}Cypher
MATCH (movie:Movie)
RETURN movie {
.title,
similar:[movieSimilar
IN apoc.cypher.runFirstColumnMany('WITH $this AS this, $first AS first, $offset AS offset MATCH (this)--(:Genre)--(o:Movie) RETURN o', {
this:movie,
first:$movieFirst,
offset:$movieOffset
}) | movieSimilar {
.title
}]
} AS movieGraphQL-Query
{
Movie {
title
similar(first:3) {
title
}
}
}Cypher Params
{
"movieFirst": 3,
"movieOffset": 0,
"movieSimilarFirst": 3
}Cypher
MATCH (movie:Movie)
RETURN movie {
.title,
similar:[movieSimilar
IN apoc.cypher.runFirstColumnMany('WITH $this AS this, $first AS first, $offset AS offset MATCH (this)--(:Genre)--(o:Movie) RETURN o', {
this:movie,
first:$movieFirst,
offset:$movieOffset
}) | movieSimilar {
.title
}][0..$movieSimilarFirst]
} AS movieGraphQL-Query
{
GenresBySubstring(substring:"Action") {
name
movies(first: 3) {
title
}
}
}Cypher Params
{
"genresBySubstringSubstring": "Action",
"genresBySubstringMoviesFirst": 3
}Cypher
UNWIND apoc.cypher.runFirstColumnMany('WITH $substring AS substring MATCH (g:Genre) WHERE toLower(g.name) CONTAINS toLower($substring) RETURN g', { substring:$genresBySubstringSubstring }) AS genresBySubstring
RETURN genresBySubstring {
.name,
movies:[(genresBySubstring)<-[:IN_GENRE]-(genresBySubstringMovies:Movie) | genresBySubstringMovies { .title }][0..$genresBySubstringMoviesFirst]
} AS genresBySubstringGraphQL-Query
mutation someMutation {
createGenre(name: "Wildlife Documentary") {
name
}
}Cypher Params
{
"createGenreName": "Wildlife Documentary"
}Cypher
CALL apoc.cypher.doIt('WITH $name AS name CREATE (g:Genre) SET g.name = name RETURN g', { name:$createGenreName }) YIELD value
WITH value[head(keys(value))] AS createGenre
RETURN createGenre { .name } AS createGenreGraphQL-Query
{
Movie(title: "River Runs Through It, A") {
title
ratings {
rating
from {
... on User {
name
userId
}
}
}
}
}Cypher Params
{
"movieTitle": "River Runs Through It, A"
}Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie {
.title,
ratings:[(movie)<-[movieRatings:RATED]-(movieRatingsFrom:User) | movieRatings {
.rating,
from:movieRatingsFrom { .name, .userId }
}]
} AS movieGraphQL-Query
{
Movie(title: "River Runs Through It, A") {
title
actors {
name
movies {
title
actors(name: "Tom Hanks") {
name
movies {
title
year
similar(first: 3) {
title
year
}
}
}
}
}
}
}Cypher Params
{
"movieTitle": "River Runs Through It, A",
"movieActorsMoviesActorsName": "Tom Hanks",
"movieActorsMoviesActorsMoviesFirst": 3,
"movieActorsMoviesActorsMoviesOffset": 0,
"movieActorsMoviesActorsMoviesSimilarFirst": 3
}Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie { .title, actors:[(movie)<-[:ACTED_IN]-(movieActors:Actor) |
movieActors { .name, movies:[(movieActors)-[:ACTED_IN]->(movieActorsMovies:Movie) |
movieActorsMovies { .title, actors:[(movieActorsMovies)<-[:ACTED_IN]-(movieActorsMoviesActors:Actor)
WHERE movieActorsMoviesActors.name = $movieActorsMoviesActorsName |
movieActorsMoviesActors { .name, movies:[(movieActorsMoviesActors)-[:ACTED_IN]->(movieActorsMoviesActorsMovies:Movie) |
movieActorsMoviesActorsMovies { .title, .year, similar:[movieActorsMoviesActorsMoviesSimilar
IN apoc.cypher.runFirstColumnMany('WITH $this AS this, $first AS first, $offset AS offset MATCH (this)--(:Genre)--(o:Movie) RETURN o', { this:movieActorsMoviesActorsMovies, first:$movieActorsMoviesActorsMoviesFirst, offset:$movieActorsMoviesActorsMoviesOffset }) |
movieActorsMoviesActorsMoviesSimilar { .title, .year }][0..$movieActorsMoviesActorsMoviesSimilarFirst] }] }] }] }] } AS movieGraphQL-Query
mutation {
actor: mergeActor(userId: "1", name: "Andrea") {
name
}
}Cypher Params
{
"actorUserId": "1",
"actorName": "Andrea"
}Cypher
MERGE (actor:Actor { userId: $actorUserId })
SET actor += { name: $actorName }
WITH actor
RETURN actor { .name } AS actorGraphQL-Query
mutation {
add: addMovieGenres(movieId: 1, genres: ["Action", "Fantasy"]) {
title
}
}Cypher Params
{
"fromMovieId": 1,
"toGenres": [
"Action",
"Fantasy"
]
}Cypher
MATCH (from:Movie { movieId: $fromMovieId })
MATCH (to:Genre) WHERE to.name IN $toGenres
MERGE (from)-[:IN_GENRE]->(to)
WITH DISTINCT from AS add
RETURN add { .title } AS addGraphQL-Query
mutation {
del: deleteMovieGenres(movieId: 1, genres: ["Action", "Fantasy"]) {
title
}
}Cypher Params
{
"fromMovieId": 1,
"toGenres": [
"Action",
"Fantasy"
]
}Cypher
MATCH (from:Movie { movieId: $fromMovieId })
MATCH (to:Genre) WHERE to.name IN $toGenres
MATCH (from)-[r:IN_GENRE]->(to)
DELETE r
WITH DISTINCT from AS del
RETURN del { .title } AS delGraphQL-Query
mutation {
add: addMoviePublishedBy(movieId: 1, publishedBy: "Company") {
title
}
}Cypher Params
{
"fromMovieId": 1,
"toPublishedBy": "Company"
}Cypher
MATCH (from:Movie { movieId: $fromMovieId })
MATCH (to:Publisher { name: $toPublishedBy })
MERGE (from)-[:PUBLISHED_BY]->(to)
WITH DISTINCT from AS add
RETURN add { .title } AS addGraphQL-Query
mutation {
del: deleteMoviePublishedBy(movieId: 1, publishedBy: "Company") {
title
}
}Cypher Params
{
"fromMovieId": 1,
"toPublishedBy": "Company"
}Cypher
MATCH (from:Movie { movieId: $fromMovieId })
MATCH (to:Publisher { name: $toPublishedBy })
MATCH (from)-[r:PUBLISHED_BY]->(to)
DELETE r
WITH DISTINCT from AS del
RETURN del { .title } AS delGraphQL-Query
mutation {
add: addUserKnows(userId: 1, knows: [10, 23]) {
name
}
}Cypher Params
{
"fromUserId": 1,
"toKnows": [
10,
23
]
}Cypher
MATCH (from:User { userId: $fromUserId })
MATCH (to:User) WHERE to.userId IN $toKnows
MERGE (from)-[:KNOWS]->(to)
WITH DISTINCT from AS add
RETURN add { .name } AS addGraphQL-Query
{
Movie(year: 2010, orderBy:title_desc, first: 10) {
title
}
}Cypher Params
{
"movieYear": 2010,
"movieFirst": 10
}Cypher
MATCH (movie:Movie)
WHERE movie.year = $movieYear
RETURN movie { .title } AS movie
ORDER BY movie.title DESC
LIMIT $movieFirstGraphQL-Query
{ Movie(orderBy:year_desc, first:10) { title } }Cypher Params
{
"movieFirst": 10
}Cypher
MATCH (movie:Movie)
RETURN movie { .title } AS movie
ORDER BY movie.year DESC LIMIT $movieFirstGraphQL-Query
{ rated(_id:1){
rating
}
}Cypher Params
{ "rated_id": 1}Cypher
MATCH ()-[rated:RATED]->()
WHERE ID(rated) = toInteger($rated_id)
RETURN rated { .rating } AS ratedGraphQL-Query
mutation {
createRated(from_userId: "1", to_movieId: "2", rating: 5) {
_id
}
}Cypher Params
{
"fromFrom_userId": "1",
"toTo_movieId": "2",
"createRatedRating": 5
}Cypher
MATCH (from:User { userId: $fromFrom_userId })
MATCH (to:Movie { movieId: $toTo_movieId })
CREATE (from)-[createRated:RATED { rating: $createRatedRating }]->(to)
WITH createRated
RETURN createRated { _id:ID(createRated) } AS createRatedGraphQL-Query
mutation {
updateRated(_id:1, rating: 5){
rating
}
}Cypher Params
{
"updateRated_id": 1,
"updateRatedRating": 5
}Cypher
MATCH ()-[updateRated:RATED]->()
WHERE ID(updateRated) = toInteger($updateRated_id)
SET updateRated = { rating: $updateRatedRating }
WITH updateRated
RETURN updateRated { .rating } AS updateRatedGraphQL-Query
mutation {
createUser(userId:1){
userId,
__typename
}
}Cypher Params
{
"createUserUserId": 1,
"createUserValidTypes": [
"User"
]
}Cypher
CREATE (createUser:User:Person { userId: $createUserUserId })
WITH createUser
RETURN createUser {
.userId,
__typename: head( [ label IN labels(createUser) WHERE label IN $createUserValidTypes ] )
} AS createUserGraphQL-Query
mutation {
addGenreMovies(name:"Action", movies: ["m1"]){
name
}
}Cypher Params
{
"fromName": "Action",
"toMovies": [
"m1"
]
}Cypher
MATCH (from:Genre { name: $fromName })
MATCH (to:Movie) WHERE to.movieId IN $toMovies
MERGE (from)-[:IN_GENRE]->(to)
WITH DISTINCT from AS addGenreMovies
RETURN addGenreMovies { .name } AS addGenreMoviesGraphQL-Query
query {
User {
born {
formatted
year
}
}
}Cypher Params
{}Cypher
MATCH (user:User)
RETURN user { born: { formatted: user.born, year: user.born.year } } AS userGraphQL-Query
query {
User {
born(formatted: "2015-06-24T12:50:35.556000000+01:00", year: 2015) {
year
}
}
}Cypher Params
{"userBornFormatted": "2015-06-24T12:50:35.556000000+01:00", "userBornYear": 2015}Cypher
MATCH (user:User)
WHERE user.born = datetime($userBornFormatted) AND user.born.year = $userBornYear
RETURN user { born: { year: user.born.year } } AS userGraphQL-Query
mutation {
actor: mergeActor(userId: "1", name: "Andrea", born: { formatted: "2015-06-24T12:50:35.556000000+01:00" }) {
name
}
}Cypher Params
{
"actorUserId": "1",
"actorName": "Andrea",
"actorBorn": {
"formatted": "2015-06-24T12:50:35.556000000+01:00"
}
}Cypher
MERGE (actor:Actor {userId:$actorUserId})
SET actor += { name: $actorName, born: datetime($actorBorn.formatted) }
WITH actor
RETURN actor { .name } AS actorGraphQL-Query
mutation {
actor: createActor(userId: "1", name: "Andrea", born: { formatted: "2015-06-24T12:50:35.556000000+01:00" }) {
name
}
}Cypher Params
{
"actorUserId": "1",
"actorName": "Andrea",
"actorBorn": {
"formatted": "2015-06-24T12:50:35.556000000+01:00"
}
}Cypher
CREATE (actor:Actor:Person {
userId: $actorUserId,
name: $actorName,
born: datetime($actorBorn.formatted)
})
WITH actor
RETURN actor { .name } AS actorGraphQL-Query
mutation {
actor: mergeActor(userId: "1", name: "Andrea", born: { year: 2018
month: 11
day: 23
hour: 10
minute: 30
second: 1
millisecond: 2
microsecond: 3
nanosecond: 4
timezone: "America/Los_Angeles" }) {
name
}
}Cypher Params
{"actorUserId": "1", "actorName": "Andrea", "actorBorn": { "year": 2018,
"month": 11,
"day": 23,
"hour": 10,
"minute": 30,
"second": 1,
"millisecond": 2,
"microsecond": 3,
"nanosecond": 4,
"timezone": "America/Los_Angeles" }}Cypher
MERGE (actor:Actor {userId:$actorUserId})
SET actor += {
name: $actorName,
born: datetime($actorBorn)
}
WITH actor
RETURN actor { .name } AS actorGraphQL-Query
mutation {
actor: createActor(userId: "1", name: "Andrea", born: { year: 2018
month: 11
day: 23
hour: 10
minute: 30
second: 1
millisecond: 2
microsecond: 3
nanosecond: 4
timezone: "America/Los_Angeles" }) {
name
born {
year
month
}
}
}Cypher Params
{"actorUserId": "1", "actorName": "Andrea", "actorBorn": { "year": 2018,
"month": 11,
"day": 23,
"hour": 10,
"minute": 30,
"second": 1,
"millisecond": 2,
"microsecond": 3,
"nanosecond": 4,
"timezone": "America/Los_Angeles" }}Cypher
CREATE (actor:Actor:Person {
userId: $actorUserId,
name: $actorName,
born: datetime($actorBorn)
})
WITH actor
RETURN actor { .name,born: { year: actor.born.year, month: actor.born.month } } AS actor