Consider the following database schema:
type Actor {
actorId: ID!
name: String
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}
type Movie {
movieId: ID!
title: String
description: String
year: Int
actors(limit: Int = 10): [Actor!]! @relationship(type: "ACTED_IN", direction: IN)
}
Now, I want to know what the top movies with most number of actors, along with the counts. The following Cypher works perfectly in Neo4j:
type Query {
getMoviesWithMostActors(limit: Int = 5): [Movie]
(
statement: """
MATCH (movie:Movie)
MATCH (movie) <-[act:ACTED_IN]- (:Actor)
WITH movie, count(act) AS actorCount
ORDER BY actorCount DESCENDING
LIMIT $limit
RETURN movie {.*, numActors: actorCount}
"""
)
}
However, it fails in GraphQL playground. I tried the following:
query {
this_works: getMoviesWithMostActorsbase(limit: 2) {
movieId
}
this_does_not_work: getMoviesWithMostActorsbase(limit: 2) {
movieId
numActors
}
}
This returned: GRAPHQL_VALIDATION_FAILED
.
"GraphQLError: Cannot query field \"numActors\" on type \"Movie\"."
My question is how do I return temporary properties without modifying the type definitions itself. And since this is a dummy example and in fact I need to do it with multiple types of nodes and with different types of scoring (int/float/array), I want to know how to do it without frequently editing the schema whenever I want to add a new query.
Known Workarounds
- Extend schema with multiple nullable properties.
- Schema needs to be changed with every new query
- Return a map and simulate a node object, as shown below.
- Need to add 2 more types for every single type of nodes
- Actual object types are lost
type MovieData {
identity: Int!
labels: [String]!
properties: Movie!
}
type MovieWithScore {
movieData: MovieData!
movieScore: String!
}
type Query {
getMoviesWithMostActors(limit: Int = 5): [MovieWithScore]
(
statement: """
MATCH (movie:Movie)
MATCH (movie) <-[act:ACTED_IN]- (:Actor)
WITH movie, count(act) AS actorCount
ORDER BY actorCount DESCENDING
LIMIT $limit
RETURN {
movieData: movie,
movieScore: 'number of actors: ' + toString(actorCount)
}
"""
)
}