You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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.

1. Vanilla JavaScript 实现多对多关系

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.

2. 迁移到GraphQL Schema

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:45:06