Processing temporary properties returned by map projections

74 Views Asked by At

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

  1. Extend schema with multiple nullable properties.
    • Schema needs to be changed with every new query
  2. 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)
                }
            """
        )
}
0

There are 0 best solutions below