The Credits Roll
A hard Data Modeling interview practice problem on DataDriven. Design the schema on the canvas: tables, keys and relationships, then get feedback on it.
- Domain
- Data Modeling
- Difficulty
- hard
- Seniority
- L4
- Asked in
- Wayfair
Problem
We run a streaming catalog where people search for films by title, by the actors in them, by the director, or by anyone else credited on the production, and also browse by genre. The same person is often credited more than once on one film, say as both its writer and its director, and every acting credit carries the character played and a billing order so the top-billed cast surface first. Design the data model behind this catalog, and outline how you would build the search architecture on top of it.
Searchable from every angle. Design it so nothing gets lost.
Worked solution and explanation
Why this problem exists in real interviews
This is a many-to-many with role attributes wearing a movie-catalog costume, and it hides a second trap: multi-attribute search at scale does not live in SQL. Persons appear on many titles in different roles, and a candidate who collapses role into a scalar on the person loses the entire query plan. Get the role placement wrong and an actor who later directs splits into two person rows, doubling them in every search result.
Break down the requirements
Step 1: Separate titles and persons
Both are first-class entities. A person has a stable identity independent of their filmography, and a title has a stable identity independent of its cast. Two dimensions, one junction.
Step 2: Model role on the junction
person_title_roles sits at the grain of one row per person per title per role, so the same person can be credited as writer and as director on one film without duplication. You can key this two ways: a composite PK on (person_id, title_id, role), or a surrogate PK alongside those three columns. Both capture the grain; the composite form makes it self-documenting, the surrogate form is friendlier to foreign keys pointing at the junction. What is NOT defensible is dropping role out of that grain.
Step 3: Separate genres into their own junction
Genres are also many-to-many with titles. Conform genres as their own small dimension with a title_genres junction rather than stuffing them into an array column on titles.
Step 4: Push search to a dedicated engine
Full-text and multi-attribute search at scale is not a SQL LIKE problem. The relational model is the source of truth; a search index (Elasticsearch, OpenSearch) is a denormalized projection rebuilt from change streams on these tables.
The solution
Below is one defensible design: two dimensions, two junctions, and a note that the search index is a projection of this relational model. Here the junction is shown with a composite key across its three grain columns; a surrogate key beside those same three columns is equally acceptable.
- titles: title_id BIGINT PK, name TEXT, release_year INT, runtime_minutes INT, content_type TEXT
- persons: person_id BIGINT PK, full_name TEXT, birth_year INT, primary_profession TEXT
- person_title_roles: person_id BIGINT PK, title_id BIGINT PK, role TEXT PK, character_name TEXT, credit_order INT
- genres: genre_id INT PK, genre_name TEXT
- title_genres: title_id BIGINT PK, genre_id INT PK
- titles references person_title_roles
- persons references person_title_roles
- titles references title_genres
- genres references title_genres
The analysis pattern
SELECT
t.name,
t.release_year,
STRING_AGG(DISTINCT g.genre_name, ', ') AS genres,
STRING_AGG(DISTINCT ptr.role, ', ') AS roles
FROM titles t
JOIN person_title_roles ptr ON ptr.title_id = t.title_id
JOIN persons p ON p.person_id = ptr.person_id
LEFT JOIN title_genres tg ON tg.title_id = t.title_id
LEFT JOIN genres g ON g.genre_id = tg.genre_id
WHERE p.full_name = 'Tilda Swinton'
GROUP BY t.name, t.release_year
ORDER BY t.release_year DESCTrade-offs and alternatives
- Relational with search index projection
- Strong relational integrity, clean updates, search index is a materialized view. Cost: two systems to keep in sync via CDC.
- Document store as source of truth
- Denormalized document per title with embedded cast and genres. Fast single-document reads. Cost: updating one actor across every title they ever appeared in is a fan-out write, and referential integrity is the application's problem.
Common follow-up questions
- How would you support searching by alias when an actor uses multiple stage names? (Tests whether the candidate adds a `person_aliases` table.)
- How would the model handle a TV series with per-episode guest appearances? (Tests adding an episode entity between title and `person_title_roles`.)
- How do you propagate a corrected release year from `titles` into the search index? (Tests CDC and search index rebuild strategy.)
- At 100M titles and 500M credits, how do you partition `person_title_roles`? (Tests sharding strategies on high-cardinality many-to-many.)