如何在Vanilla JavaScript及GraphQL中实现电影与演员的多对多关系
Got it, let's walk through how to set up this many-to-many relationship first in vanilla JavaScript, then translate that to a GraphQL schema. This is a common pattern, so let's break it down clearly.
For many-to-many relationships (where a movie can have multiple actors, and an actor can appear in multiple movies), the key is using a join table (or association table) to map the IDs of movies to actors. This avoids redundant data and keeps updates consistent.
Here's a complete implementation:
// Your original datasets let movies = [ { id: '1', title: 'Erin Brockovich'}, { id: '2', title: 'A Good Year'}, { id: '3', title: 'A Beautiful Mind'}, { id: '4', title: 'Gladiator'} ]; let actors = [ { id: 'a', name: 'Julia Roberts'}, { id: 'b', name: 'Albert Finney'}, { id: 'c', name: 'Russell Crowe'} ]; // Join table: Maps movie IDs to actor IDs (the core of many-to-many) const movieActors = [ { movieId: '1', actorId: 'a' }, // Erin Brockovich → Julia Roberts { movieId: '1', actorId: 'b' }, // Erin Brockovich → Albert Finney { movieId: '3', actorId: 'c' }, // A Beautiful Mind → Russell Crowe { movieId: '4', actorId: 'c' }, // Gladiator → Russell Crowe { movieId: '2', actorId: 'c' } // A Good Year → Russell Crowe ]; // Helper: Get all actors for a given movie function getActorsByMovieId(movieId) { return movieActors .filter(assoc => assoc.movieId === movieId) .map(assoc => actors.find(actor => actor.id === assoc.actorId)) .filter(Boolean); // Filter out any invalid entries (if IDs don't match) } // Helper: Get all movies for a given actor function getMoviesByActorId(actorId) { return movieActors .filter(assoc => assoc.actorId === actorId) .map(assoc => movies.find(movie => movie.id === assoc.movieId)) .filter(Boolean); } // Example usage console.log(getActorsByMovieId('1')); // Output: [{ id: 'a', name: 'Julia Roberts' }, { id: 'b', name: 'Albert Finney' }] console.log(getMoviesByActorId('c')); // Output: [{ id: '3', ... }, { id: '4', ... }, { id: '2', ... }]
Why use a join table instead of adding an actors array directly to each movie (or vice versa)? Because if you duplicate actor data across movies, updating an actor's name would require changing it in every movie entry they're in—this is error-prone. The join table keeps relationships decoupled from the actual entity data.
Now let's translate this to a GraphQL schema, which will let clients query related data in a single request. We'll define types for Movie and Actor, then use resolvers to fetch the related entities via our join table.
Step 1: Define the GraphQL Schema
# Root query type type Query { # Get a single movie by ID movie(id: ID!): Movie # Get a single actor by ID actor(id: ID!): Actor # Get all movies movies: [Movie!]! # Get all actors actors: [Actor!]! } # Movie type with a reference to its actors type Movie { id: ID! title: String! # Many-to-many: A movie has multiple actors actors: [Actor!]! } # Actor type with a reference to their movies type Actor { id: ID! name: String! # Many-to-many: An actor has multiple movies movies: [Movie!]! }
Step 2: Implement the Resolvers
Resolvers tell GraphQL how to fetch the related data. We'll reuse our vanilla JS logic here:
// Reuse your existing movies, actors, and movieActors data const resolvers = { Query: { movie: (_, { id }) => movies.find(movie => movie.id === id), actor: (_, { id }) => actors.find(actor => actor.id === id), movies: () => movies, actors: () => actors }, // Resolve actors for a Movie Movie: { actors: (parent) => { // `parent` is the current Movie object return movieActors .filter(assoc => assoc.movieId === parent.id) .map(assoc => actors.find(actor => actor.id === assoc.actorId)) .filter(Boolean); } }, // Resolve movies for an Actor Actor: { movies: (parent) => { // `parent` is the current Actor object return movieActors .filter(assoc => assoc.actorId === parent.id) .map(assoc => movies.find(movie => movie.id === assoc.movieId)) .filter(Boolean); } } };
Example GraphQL Query
Now clients can query a movie and its actors in one go:
query GetMovieWithActors { movie(id: "1") { title actors { name } } }
Or query an actor and their movies:
query GetActorWithMovies { actor(id: "c") { name movies { title } } }
This setup mirrors the vanilla JS relationship but gives clients the flexibility to request exactly the data they need.
内容的提问来源于stack exchange,提问作者Tylik Stec

