Document database: Getting started

This tutorial will help you get started with our document-oriented database, DoctorWho. We query DoctorWho by writing Java code. The Java interface to DoctorWho is documented here: Java documentation.

Setting up DoctorWho

As in the previous practicals on relational databases and graph databases, we have prepared a dataset of movies and people (actors, directors, etc.) based on IMDb.

The document database is here: document-movie-db.zip. Unpack the zip file, which should give you a subdirectory called document-movie-db.

To download the database system itself, go to document-db.jar. Put this jar file in the same directory that contains the directory document-movie-db. Now you are ready to explore the data.

Looking up a movie by ID

The document database contains JSON objects. Each object is identified by a unique number, its ID. There are two types of objects representing movies and people. Let's write a program to look up the details of this movie in one of our databases, and print them out. The following code will take two arguments: the directory of the database and a movie's ID:

import uk.ac.cam.cl.databases.moviedb.MovieDB;
import uk.ac.cam.cl.databases.moviedb.model.*;

public class GetMovieById {
    public static void main(String[] args) {
        try (MovieDB database = MovieDB.open(args[0])) {
            int id = Integer.parseInt(args[1]);
            Movie movie = database.getMovieById(id);
            System.out.println(movie);
        }
    }
}

The ID of the latest Star Wars movie is 4148060. How do we look it up? Put the above Java code in a file called GetMovieById.java in the same directory as the jar file you downloaded. You can then compile and run the example as follows (if you are running Microsoft Windows):

# On Windows
javac -classpath document-db.jar GetMovieById.java
java -classpath .;document-db.jar GetMovieById document-movie-db 4148060

If you are running Linux or Mac OS, the commands are very similar -- you just need to replace the semicolon with a colon in the second command:

# On Linux or Mac OS
javac -classpath document-db.jar GetMovieById.java
java -classpath .:document-db.jar GetMovieById document-movie-db 4148060

The command-line argument document-movie-db is the name of the directory containing the database.

When you run the program, the output should look like this:

{
  "id": 4148060,
  "title": "Star Wars: Episode VII - The Force Awakens (2015)",
  "year": 2015,
  "actors": [
    {
      "character": "Han Solo",
      "position": 1,
      "person_id": 764566,
      "name": "Ford, Harrison (I)"
    },
    {
      "character": "Luke Skywalker",
      "position": 2,
      "person_id": 953810,
      "name": "Hamill, Mark (I)"
    },
    {
      "character": "Princess Leia",
      "position": 3,
      "person_id": 3060717,
      "name": "Fisher, Carrie (I)"
    },
    {
      "character": "Kylo Ren",
      "position": 4,
      "person_id": 637045,
      "name": "Driver, Adam (I)"
    },
    {
      "character": "Rey",
      "position": 5,
      "person_id": 3744508,
      "name": "Ridley, Daisy"
    },
    {
      "character": "Finn",
      "position": 6,
      "person_id": 269206,
      "name": "Boyega, John"
    },
    {
      "character": "Poe Dameron",
      "position": 7,
      "person_id": 1100464,
      "name": "Isaac, Oscar"
    },
    {
      "character": "Maz Kanata",
      "position": 8,
      "person_id": 3611517,
      "name": "Nyong\u0027o, Lupita"
    },
    {
      "character": "Supreme Leader Snoke",
      "position": 9,
      "person_id": 2150950,
      "name": "Serkis, Andy"
    },
    {
      "character": "General Hux",
      "position": 10,
      "person_id": 861587,
      "name": "Gleeson, Domhnall"
    },
    {
      "character": "C-3PO",
      "position": 11,
      "person_id": 534256,
      "name": "Daniels, Anthony (I)"
    },
    {
      "character": "Lor San Tekka",
      "position": 12,
      "person_id": 2488301,
      "name": "von Sydow, Max (I)"
    },
    {
      "character": "Chewbacca",
      "position": 13,
      "person_id": 1525145,
      "name": "Mayhew, Peter (II)"
    },
    {
      "character": "Captain Phasma",
      "position": 14,
      "person_id": 2885478,
      "name": "Christie, Gwendoline"
    },
    {
      "character": "Chewbacca Double",
      "position": 15,
      "person_id": 2303814,
      "name": "Suotamo, Joonas"
    },
    {
      "character": "Lead Stormtrooper",
      "position": 16,
      "person_id": 63603,
      "name": "Andersen, Pip"
    },
    {
      "character": "Unkar Plutt",
      "position": 17,
      "person_id": 1832367,
      "name": "Pegg, Simon"
    },
    {
      "character": "Teedo",
      "position": 18,
      "person_id": 2157557,
      "name": "Shah, Kiran"
    },
    {
      "character": "Jakku Villager",
      "position": 19,
      "person_id": 3084261,
      "name": "Frost, Sasha (II)"
    },
    {
      "character": "Colonel Kaplan",
      "position": 20,
      "person_id": 2389098,
      "name": "Torrens, Pip"
    },
    {
      "character": "Major Ematt",
      "position": 21,
      "person_id": 1108884,
      "name": "Jack, Andrew (I)"
    },
    {
      "character": "Colonel Datoo",
      "position": 22,
      "person_id": 1492590,
      "name": "Marshall, Rocky"
    },
    {
      "character": "Snap Wexley",
      "position": 23,
      "person_id": 917767,
      "name": "Grunberg, Greg"
    },
    {
      "character": "Brance",
      "position": 24,
      "person_id": 680016,
      "name": "Elliott, Emun"
    },
    {
      "character": "Bala-Tik",
      "position": 25,
      "person_id": 2466777,
      "name": "Vernel, Brian"
    },
    {
      "character": "Tasu Leech",
      "position": 26,
      "person_id": 2051967,
      "name": "Ruhian, Yayan"
    },
    {
      "character": "Lieutenant Mitaka",
      "position": 27,
      "person_id": 90655,
      "name": "Armesto, Sebastian"
    },
    {
      "character": "Korr Sella",
      "position": 28,
      "person_id": 3742999,
      "name": "Richardson-Sellers, Maisie"
    },
    {
      "character": "Wollivan",
      "position": 29,
      "person_id": 550881,
      "name": "Davis, Warwick (I)"
    },
    {
      "character": "Young Rey",
      "position": 30,
      "person_id": 3063578,
      "name": "Fleming, Cailey"
    },
    {
      "character": "Knight of Ren",
      "position": 31,
      "person_id": 2260553,
      "name": "Stanley, Mark (VI)"
    },
    {
      "character": "Admiral Statura",
      "position": 32,
      "person_id": 1370421,
      "name": "Leung, Ken (I)"
    },
    {
      "character": "Razoo Quin-Fee",
      "position": 33,
      "person_id": 2431715,
      "name": "Uwais, Iko"
    },
    {
      "character": "Bazine Netal",
      "position": 34,
      "person_id": 2807197,
      "name": "Brewster, Anna"
    },
    {
      "character": "Dr. Kalonia",
      "position": 35,
      "person_id": 4028259,
      "name": "Walter, Harriet"
    },
    {
      "character": "Admiral Ackbar",
      "position": 36,
      "person_id": 2033637,
      "name": "Rose, Tim (I)"
    },
    {
      "character": "Admiral Ackbar",
      "position": 37,
      "person_id": 166778,
      "name": "Bauersfeld, Erik",
      "note": "(voice)"
    },
    {
      "character": "Nien Nunb",
      "position": 38,
      "person_id": 1925154,
      "name": "Quinn, Mike (I)"
    },
    {
      "character": "Nien Nunb",
      "position": 39,
      "person_id": 2041516,
      "name": "Rotich, Kipsang",
      "note": "(voice)"
    },
    {
      "character": "FN-3181",
      "position": 40,
      "person_id": 845010,
      "name": "Giacchino, Michael"
    },
    {
      "character": "FN-9330",
      "position": 41,
      "person_id": 865963,
      "name": "Godrich, Nigel"
    },
    {
      "character": "Bar Patron",
      "position": 42,
      "person_id": 787762,
      "name": "Friedlander, Judah"
    },
    {
      "character": "Bar Patron",
      "position": 43,
      "person_id": 1546632,
      "name": "McGuire, Victor"
    },
    {
      "character": "Bar Patron",
      "position": 44,
      "person_id": 2611738,
      "name": "Yerolemou, Miltos"
    },
    {
      "character": "Bar Patron",
      "position": 45,
      "person_id": 3422900,
      "name": "Longrigg, Francesca"
    },
    {
      "character": "Bar Patron",
      "position": 46,
      "person_id": 151558,
      "name": "Barns, D.C.",
      "note": "(as D.C. Barnes)"
    },
    {
      "character": "Bar Patron",
      "position": 47,
      "person_id": 1150815,
      "name": "Johnson, Matt (LXXXV)"
    },
    {
      "character": "Lieutenant Connix",
      "position": 48,
      "person_id": 3427694,
      "name": "Lourd, Billie"
    },
    {
      "character": "Min Sakul",
      "position": 49,
      "person_id": 2766226,
      "name": "Best, Leanne"
    },
    {
      "character": "Ensign Goode",
      "position": 50,
      "person_id": 2892417,
      "name": "Clarke, Crystal (I)"
    },
    {
      "character": "Rear Admiral Guich",
      "position": 51,
      "person_id": 1247480,
      "name": "Kissoon, Jeffery"
    },
    {
      "character": "Lema Eelyak",
      "position": 52,
      "person_id": 3833280,
      "name": "Sermbezis, Claudia"
    },
    {
      "character": "Captain Cypress",
      "position": 53,
      "person_id": 7630,
      "name": "Abrams, Gerald W.",
      "note": "(as Gerry Abrams)"
    },
    {
      "character": "Vice Admiral Resdox",
      "position": 54,
      "person_id": 1545334,
      "name": "McGrath, Jim (VIII)"
    },
    {
      "character": "Tabala Zo",
      "position": 55,
      "person_id": 3808922,
      "name": "Saunders, Philicia"
    },
    {
      "character": "Commodore Meta",
      "position": 56,
      "person_id": 2939843,
      "name": "Dameron, Morgan"
    },
    {
      "character": "Jess Testor",
      "position": 57,
      "person_id": 3200604,
      "name": "Henwick, Jessica"
    },
    {
      "character": "Lieutenant Bastian",
      "position": 58,
      "person_id": 456849,
      "name": "Cole, Tosin"
    },
    {
      "character": "Niv Lek",
      "position": 59,
      "person_id": 1529064,
      "name": "McArdle, James (IV)"
    },
    {
      "character": "Yolo Ziff",
      "position": 60,
      "person_id": 917122,
      "name": "Grube, Stefan"
    },
    {
      "character": "Resistance Soldier",
      "position": 61,
      "person_id": 92971,
      "name": "Arnold, Dixie"
    },
    {
      "character": "First Order Officer",
      "position": 62,
      "person_id": 3273080,
      "name": "John-Kamen, Hannah"
    },
    {
      "character": "First Order Officer",
      "position": 63,
      "person_id": 664089,
      "name": "Edden, Tom"
    },
    {
      "character": "First Order Officer",
      "position": 64,
      "person_id": 3063369,
      "name": "Fleetwood, Kate"
    },
    {
      "character": "First Order Officer",
      "position": 65,
      "person_id": 1987358,
      "name": "Riddell, Richard (I)"
    },
    {
      "character": "First Order Officer",
      "position": 66,
      "person_id": 948819,
      "name": "Hall, Jefferson"
    },
    {
      "character": "First Order Officer",
      "position": 67,
      "person_id": 292048,
      "name": "Brodie-Sangster, Thomas"
    },
    {
      "character": "First Order Officer",
      "position": 68,
      "person_id": 1331978,
      "name": "Laskey, Jack"
    },
    {
      "character": "First Order Stormtrooper/Resistance Fighter",
      "person_id": 28581,
      "name": "Akin, Charlie",
      "note": "(uncredited)"
    },
    {
      "character": "Rebel Soldier",
      "person_id": 44487,
      "name": "Allan, Adrian (I)",
      "note": "(uncredited)"
    },
    {
      "character": "First Order Stormtrooper",
      "person_id": 2676016,
      "name": "Alleyne, Samantha",
      "note": "(uncredited)"
    },
    {
      "character": "First Order Snowtrooper",
      "person_id": 2647893,
      "name": "Ásberg, Joshua",
      "note": "(uncredited)"
    },
    {
      "character": "X-Wing pilot",
      "person_id": 215267,
      "name": "Biddiss, Paul",
      "note": "(uncredited)"
    },
    {
      "character": "First Order Officer",
      "person_id": 2778116,
      "name": "Blamires, Hannah",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance PA Announcer",
      "person_id": 2782012,
      "name": "Blue, Verona",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "First Order Admiral",
      "person_id": 286660,
      "name": "Bridges, Rony",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 287105,
      "name": "Briggins, Dante",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 314018,
      "name": "Budd, Stuart",
      "note": "(uncredited)"
    },
    {
      "character": "Heavy Gunner Stormtrooper",
      "person_id": 399206,
      "name": "Chambers, Jamie B.",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 420817,
      "name": "Chimes, Alan",
      "note": "(uncredited)"
    },
    {
      "person_id": 2883398,
      "name": "Chong, Christina",
      "note": "(scenes deleted)"
    },
    {
      "character": "Bus Stop Boy",
      "person_id": 432974,
      "name": "Chwu, Jordan",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 443584,
      "name": "Clay, Jamie (I)",
      "note": "(uncredited)"
    },
    {
      "character": "First Order General",
      "person_id": 458932,
      "name": "Collaco, Bern",
      "note": "(uncredited)"
    },
    {
      "character": "Tie Fighter Pilot/Elite Special Forces Tie Pilot",
      "person_id": 459413,
      "name": "Collett, Mark Everex",
      "note": "(uncredited)"
    },
    {
      "character": "Hangar Officer/Forest Stormtrooper",
      "person_id": 460705,
      "name": "Collins, David W.",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Resistance Medic",
      "person_id": 483794,
      "name": "Correll, Patrick",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Storm Trooper",
      "person_id": 494733,
      "name": "Cox, Rowan",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 496315,
      "name": "Craig, Daniel (I)",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 505690,
      "name": "Crouch, Paul (III)",
      "note": "(uncredited)"
    },
    {
      "character": "PZ-4CO",
      "person_id": 2932911,
      "name": "Cuzner, Nathalie",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 533999,
      "name": "Daniel, Rimmel",
      "note": "(uncredited)"
    },
    {
      "character": "Goss Toowers",
      "person_id": 566769,
      "name": "De\u0027Winter, Keith",
      "note": "(uncredited)"
    },
    {
      "character": "Knight of Ren",
      "person_id": 601995,
      "name": "Dickins, Michael",
      "note": "(uncredited)"
    },
    {
      "character": "Niima Scavenger",
      "person_id": 616198,
      "name": "Dodson, Mark (I)",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Imperial Gunner",
      "person_id": 621639,
      "name": "Donald, Nick",
      "note": "(uncredited)"
    },
    {
      "character": "Starkiller PA Announcer",
      "person_id": 624155,
      "name": "Donovan, Michael (III)",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Jakku Villager",
      "person_id": 666998,
      "name": "Edwards, Cameron (VI)",
      "note": "(uncredited)"
    },
    {
      "character": "Snowtrooper",
      "person_id": 730481,
      "name": "Ferm, Darl",
      "note": "(uncredited)"
    },
    {
      "character": "X-Wing Pilot",
      "person_id": 780336,
      "name": "François, Sternkiker",
      "note": "(uncredited)"
    },
    {
      "character": "Maz\u0027s Bar Pirate",
      "person_id": 792083,
      "name": "Fryer-Kelsey, Mick",
      "note": "(uncredited)"
    },
    {
      "character": "First Order Stormtrooper",
      "person_id": 796136,
      "name": "Fullington, Jesse Michael",
      "note": "(uncredited)"
    },
    {
      "character": "Jakku Defender",
      "person_id": 3097591,
      "name": "Garcia, Gloria (IX)",
      "note": "(uncredited)"
    },
    {
      "character": "Bar Patron",
      "person_id": 821278,
      "name": "Gardner, Salo",
      "note": "(uncredited)"
    },
    {
      "character": "Rebel Alliance",
      "person_id": 3101016,
      "name": "Garnell, Caroline",
      "note": "(uncredited)"
    },
    {
      "character": "First Order Officer",
      "person_id": 832912,
      "name": "Geden, Chris",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 854706,
      "name": "Gilron, Erez",
      "note": "(uncredited)"
    },
    {
      "character": "Friend of Big Toad",
      "person_id": 3121114,
      "name": "Glass, Clare",
      "note": "(uncredited)"
    },
    {
      "character": "Snowtrooper",
      "person_id": 910957,
      "name": "Griffiths, Steven (III)",
      "note": "(uncredited)"
    },
    {
      "character": "Obi-Wan Kenobi",
      "person_id": 925324,
      "name": "Guinness, Alec",
      "note": "(archive sound) (uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 3177896,
      "name": "Hargreaves, Amybeth",
      "note": "(uncredited)"
    },
    {
      "character": "Bar Worker",
      "person_id": 3191086,
      "name": "Hayter, Marina",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance Fighter",
      "person_id": 1035396,
      "name": "Hobbs, Matthew (III)",
      "note": "(uncredited)"
    },
    {
      "character": "X-Wing Pilot",
      "person_id": 1036982,
      "name": "Hodges, Phil (III)",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 1043367,
      "name": "Holland, Leigh (I)",
      "note": "(uncredited)"
    },
    {
      "character": "Rebel Alliance",
      "person_id": 1068893,
      "name": "Hudson, Kevin (IX)",
      "note": "(uncredited)"
    },
    {
      "character": "Niima Scavenger",
      "person_id": 3233979,
      "name": "Huie, Karen",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 1121307,
      "name": "James, Phoenix (I)",
      "note": "(uncredited)"
    },
    {
      "character": "Fun House Officer",
      "person_id": 1121950,
      "name": "James-Samuels, Tobias",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 1121929,
      "name": "James, Zander",
      "note": "(uncredited)"
    },
    {
      "character": "Hosnian Citizen/Starkiller Technician",
      "person_id": 1187954,
      "name": "Kane, Tom (II)",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Ello Asty",
      "person_id": 1197556,
      "name": "Kasey, Paul (I)",
      "note": "(uncredited)"
    },
    {
      "character": "Cloaked Messenger",
      "person_id": 1217356,
      "name": "Kennedy, Aaron (IV)",
      "note": "(uncredited)"
    },
    {
      "character": "Tie Fighter Pilot",
      "person_id": 1256101,
      "name": "Knight, Aidan (II)",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance Engineer",
      "person_id": 1285550,
      "name": "Krishnan, Sanj",
      "note": "(uncredited)"
    },
    {
      "character": "X-Wing Pilot",
      "person_id": 1320073,
      "name": "Landau, Lukas",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance Soldier",
      "person_id": 1362633,
      "name": "Lenart, Andrei",
      "note": "(uncredited)"
    },
    {
      "character": "Rebel Alliance",
      "person_id": 1364378,
      "name": "Leon Martinez, Jorge",
      "note": "(uncredited)"
    },
    {
      "character": "Dasha Promenti",
      "person_id": 3398349,
      "name": "Leonte, Ana-Maria",
      "note": "(uncredited)"
    },
    {
      "character": "Hangar Officer/Starkiller Stormtrooper",
      "person_id": 1381074,
      "name": "Libran, Devon",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 1442963,
      "name": "Machin, Billy James",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 1445449,
      "name": "Mackinnon, Andrew (III)",
      "note": "(uncredited)"
    },
    {
      "character": "Jakku Villager",
      "person_id": 1463049,
      "name": "Malik, Hamza",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 1467395,
      "name": "Mamrak, Raymond",
      "note": "(uncredited)"
    },
    {
      "character": "First Order Stormtrooper",
      "person_id": 1528003,
      "name": "Mbanefo, Kenny-Lee",
      "note": "(uncredited)"
    },
    {
      "character": "Bar Patron",
      "person_id": 1531600,
      "name": "McCarrison, David (III)",
      "note": "(uncredited)"
    },
    {
      "character": "Obi-Wan Kenobi",
      "person_id": 1545767,
      "name": "McGregor, Ewan",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Bar Patron",
      "person_id": 3532442,
      "name": "Mills, Francesca",
      "note": "(uncredited)"
    },
    {
      "character": "First Order Stormtrooper",
      "person_id": 1618439,
      "name": "Mohan, Sandeep (III)",
      "note": "(uncredited)"
    },
    {
      "character": "Officer of the Rebel Alliance",
      "person_id": 1669097,
      "name": "Murphy, Benjayx",
      "note": "(uncredited)"
    },
    {
      "character": "Bar Patron",
      "person_id": 1708193,
      "name": "Nevett, Charlie (I)",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 1714349,
      "name": "Nicholls, Jason (V)",
      "note": "(uncredited)"
    },
    {
      "character": "HoM 56",
      "person_id": 1726135,
      "name": "Noble, Terry (II)",
      "note": "(uncredited)"
    },
    {
      "character": "Politician",
      "person_id": 1730341,
      "name": "Norfolk, David",
      "note": "(uncredited)"
    },
    {
      "character": "Yoda",
      "person_id": 1785998,
      "name": "Oz, Frank",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Scavenger",
      "person_id": 1864525,
      "name": "Pickup, Mark",
      "note": "(uncredited)"
    },
    {
      "character": "Athgar Heece",
      "person_id": 3678344,
      "name": "Pickup, Mel",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance Member",
      "person_id": 3684248,
      "name": "Pittaway, Gillian",
      "note": "(uncredited)"
    },
    {
      "character": "Rosser Weno",
      "person_id": 1897219,
      "name": "Powell, Elroy",
      "note": "(uncredited)"
    },
    {
      "character": "Crokind Shand",
      "person_id": 1933623,
      "name": "Rahman, Cecep Arif",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 1992092,
      "name": "Rincon, Jay",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance Fighter",
      "person_id": 2026780,
      "name": "Romeo, Julio",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 3773484,
      "name": "Rothschild, Alexsandria",
      "note": "(uncredited)"
    },
    {
      "character": "First Order Stormtrooper",
      "person_id": 2059499,
      "name": "Rutter, Mark Flynn",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance Technician",
      "person_id": 3793773,
      "name": "Salenger, Meredith",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "First Order Stormtrooper/Snowtrooper Commander/Heavy Gunner Stormtrooper",
      "person_id": 2093666,
      "name": "Santana, David M.",
      "note": "(uncredited)"
    },
    {
      "character": "Desert Scavenger",
      "person_id": 3820452,
      "name": "Schuchmacher, Orly",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Power Droid",
      "person_id": 3836680,
      "name": "Shah, Arti",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance Medic/Forest Stormtrooper",
      "person_id": 3844243,
      "name": "Sheridan, Kat",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "ME-8D9",
      "person_id": 3854318,
      "name": "Silva, Stephanie (IV)",
      "note": "(uncredited)"
    },
    {
      "character": "Senior Resistance Officer",
      "person_id": 2207504,
      "name": "Skinner, Jasper",
      "note": "(uncredited)"
    },
    {
      "character": "Lady Astronaut",
      "person_id": 3864906,
      "name": "Slade, Sandy Kate",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance Fighter",
      "person_id": 2230225,
      "name": "So, Clem (I)",
      "note": "(uncredited)"
    },
    {
      "character": "Red Eyed Sand Alien",
      "person_id": 2258518,
      "name": "Stambler, Robert (II)",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Jakku Village Elder",
      "person_id": 3895385,
      "name": "Steele, Karol",
      "note": "(uncredited)"
    },
    {
      "character": "Rebel General",
      "person_id": 2283202,
      "name": "Stone, Frank (V)",
      "note": "(uncredited)"
    },
    {
      "character": "X-Wing Pilot",
      "person_id": 2311712,
      "name": "Sweet, Andy (III)",
      "note": "(uncredited)"
    },
    {
      "character": "Hangar Officer/Starkiller Technician",
      "person_id": 3926723,
      "name": "Taber, Catherine",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Niima Scavenger/Forest Stormtrooper",
      "person_id": 2337075,
      "name": "Tatasciore, Fred",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "First Order Stormtrooper",
      "person_id": 2341349,
      "name": "Taylor, James Arnold",
      "note": "(uncredited)"
    },
    {
      "character": "R2-D2",
      "person_id": 2458521,
      "name": "Vee, Jimmy",
      "note": "(uncredited)"
    },
    {
      "character": "Stormtrooper",
      "person_id": 2508139,
      "name": "Walters, Nick (VIII)",
      "note": "(uncredited)"
    },
    {
      "character": "Bar Patron",
      "person_id": 2512111,
      "name": "Ward, Ashley (XIII)",
      "note": "(uncredited)"
    },
    {
      "character": "Varmik",
      "person_id": 2516121,
      "name": "Warren, Paul (VI)",
      "note": "(uncredited)"
    },
    {
      "character": "Resistance Fighter",
      "person_id": 4048755,
      "name": "White, Kelsey (IV)",
      "note": "(uncredited)"
    },
    {
      "character": "Bollie Prindel/Roodown",
      "person_id": 2551246,
      "name": "Whyte, Ian (II)",
      "note": "(uncredited)"
    },
    {
      "character": "Ello Asty/Quiggold/Niima Thug",
      "person_id": 2588133,
      "name": "Wood, Matthew (I)",
      "note": "(voice) (uncredited)"
    },
    {
      "character": "Ubert Quaril",
      "person_id": 2594073,
      "name": "Wresniwiro, Topo",
      "note": "(uncredited)"
    },
    {
      "character": "FN-2199",
      "person_id": 2606587,
      "name": "Yang, Liang (I)",
      "note": "(uncredited)"
    }
  ],
  "cinematographers": [
    {
      "person_id": 1603590,
      "name": "Mindel, Dan",
      "note": "(director of photography)"
    }
  ],
  "composers": [
    {
      "person_id": 2563455,
      "name": "Williams, John (I)",
      "note": "(music by)"
    }
  ],
  "costume_designers": [
    {
      "person_id": 1190879,
      "name": "Kaplan, Michael (I)"
    }
  ],
  "directors": [
    {
      "person_id": 7647,
      "name": "Abrams, J.J."
    }
  ],
  "editors": [
    {
      "person_id": 2802556,
      "name": "Brandon, Maryann"
    },
    {
      "person_id": 3469916,
      "name": "Markey, Mary Jo"
    }
  ],
  "producers": [
    {
      "person_id": 7647,
      "name": "Abrams, J.J.",
      "note": "(producer)"
    },
    {
      "person_id": 4908396,
      "name": "Anderson, Pippa",
      "note": "(co-producer)"
    },
    {
      "person_id": 92356,
      "name": "Arndt, Michael (II)",
      "note": "(associate producer)"
    },
    {
      "person_id": 321756,
      "name": "Burk, Bryan",
      "note": "(producer)"
    },
    {
      "person_id": 526047,
      "name": "Dagfinnsson, Leifur B.",
      "note": "(line producer: Iceland) (as Leifur Dagfinnsson)"
    },
    {
      "person_id": 884928,
      "name": "Gormley, Tommy",
      "note": "(co-producer)"
    },
    {
      "person_id": 971135,
      "name": "Harper, Tommy (V)",
      "note": "(executive producer)"
    },
    {
      "person_id": 1197441,
      "name": "Kasdan, Lawrence",
      "note": "(co-producer) (uncredited)"
    },
    {
      "person_id": 3313970,
      "name": "Kennedy, Kathleen (I)",
      "note": "(producer)"
    },
    {
      "person_id": 1542919,
      "name": "McGatlin, Jason D.",
      "note": "(executive producer) (as Jason McGatlin)"
    },
    {
      "person_id": 3733781,
      "name": "Rejwan, Michelle",
      "note": "(co-producer)"
    },
    {
      "person_id": 2034928,
      "name": "Rosenblatt, Ben (I)",
      "note": "(co-producer)"
    },
    {
      "person_id": 2310915,
      "name": "Swartz, John (I)",
      "note": "(co-producer)"
    },
    {
      "person_id": 5394730,
      "name": "Towner, Susan",
      "note": "(co-producer)"
    }
  ],
  "writers": [
    {
      "line_order": 1,
      "group_order": 1,
      "subgroup_order": 1,
      "person_id": 1197441,
      "name": "Kasdan, Lawrence",
      "note": "(written by)"
    },
    {
      "line_order": 1,
      "group_order": 1,
      "subgroup_order": 2,
      "person_id": 7647,
      "name": "Abrams, J.J.",
      "note": "(written by)"
    },
    {
      "line_order": 1,
      "group_order": 2,
      "subgroup_order": 2,
      "person_id": 92356,
      "name": "Arndt, Michael (II)",
      "note": "(written by)"
    },
    {
      "line_order": 2,
      "group_order": 1,
      "subgroup_order": 1,
      "person_id": 1421323,
      "name": "Lucas, George (I)",
      "note": "(based on characters created by)"
    }
  ],
  "certificates": [
    {
      "country": "Argentina",
      "certificate": "13"
    },
    {
      "country": "Australia",
      "certificate": "M",
      "note": "(certificate #268462)"
    },
    {
      "country": "Austria",
      "certificate": "12"
    },
    {
      "country": "Brazil",
      "certificate": "12"
    },
    {
      "country": "Canada",
      "certificate": "G",
      "note": "(Québec)"
    },
    {
      "country": "Canada",
      "certificate": "PG"
    },
    {
      "country": "Chile",
      "certificate": "TE+7"
    },
    {
      "country": "Denmark",
      "certificate": "11"
    },
    {
      "country": "Finland",
      "certificate": "K-12"
    },
    {
      "country": "France",
      "certificate": "Tous publics"
    },
    {
      "country": "Germany",
      "certificate": "12"
    },
    {
      "country": "Hong Kong",
      "certificate": "IIA"
    },
    {
      "country": "Hungary",
      "certificate": "12"
    },
    {
      "country": "India",
      "certificate": "U"
    },
    {
      "country": "Indonesia",
      "certificate": "13+",
      "note": "(DVD rating)"
    },
    {
      "country": "Indonesia",
      "certificate": "SU"
    },
    {
      "country": "Ireland",
      "certificate": "12",
      "note": "(DVD rating)"
    },
    {
      "country": "Ireland",
      "certificate": "12A"
    },
    {
      "country": "Italy",
      "certificate": "T"
    },
    {
      "country": "Japan",
      "certificate": "G"
    },
    {
      "country": "Malaysia",
      "certificate": "P13"
    },
    {
      "country": "Mexico",
      "certificate": "B"
    },
    {
      "country": "Netherlands",
      "certificate": "12"
    },
    {
      "country": "New Zealand",
      "certificate": "M"
    },
    {
      "country": "Norway",
      "certificate": "12"
    },
    {
      "country": "Philippines",
      "certificate": "PG-13"
    },
    {
      "country": "Poland",
      "certificate": "12"
    },
    {
      "country": "Portugal",
      "certificate": "M/12"
    },
    {
      "country": "Russia",
      "certificate": "12+"
    },
    {
      "country": "Singapore",
      "certificate": "PG"
    },
    {
      "country": "South Korea",
      "certificate": "12"
    },
    {
      "country": "Spain",
      "certificate": "7"
    },
    {
      "country": "Sweden",
      "certificate": "11"
    },
    {
      "country": "Switzerland",
      "certificate": "12"
    },
    {
      "country": "Taiwan",
      "certificate": "GP"
    },
    {
      "country": "Thailand",
      "certificate": "G"
    },
    {
      "country": "UK",
      "certificate": "12",
      "note": "(DVD rating)"
    },
    {
      "country": "UK",
      "certificate": "12A"
    },
    {
      "country": "USA",
      "certificate": "PG-13",
      "note": "(certificate #50155)"
    }
  ],
  "genres": [
    "Action",
    "Adventure",
    "Fantasy",
    "Sci-Fi"
  ],
  "keywords": [
    "2010s",
    "abandoned-ship",
    "action-hero",
    "action-heroine",
    "actor-reprises-previous-role",
    "admiral",
    "advanced-technology",
    "adventure-hero",
    "aerial-shot",
    "air-strike",
    "alien",
    "alien-creature",
    "ambiguous-ending",
    "ambush",
    "anger",
    "anti-hero",
    "anti-heroine",
    "army",
    "arrest",
    "assassin",
    "asteroid-belt",
    "astromech-droid",
    "attack",
    "bar",
    "bar-scene",
    "bartender",
    "battle",
    "battlecruiser",
    "battlecruiser-starship",
    "battlefield",
    "betrayal",
    "bilingualism",
    "binoculars",
    "bipedal-alien",
    "blaster-pistol",
    "blizzard",
    "blockbuster",
    "blood",
    "blue-blade-lightsaber",
    "bombardment",
    "bounty-hunter",
    "bravery",
    "brawl",
    "british-african",
    "brutality",
    "cannon",
    "cape",
    "captain",
    "caucasian",
    "cellar",
    "chaos",
    "character-repeating-someone-else\u0027s-dialogue",
    "character-says-i-have-a-bad-feeling-about-this",
    "character-says-may-the-force-be-with-you",
    "chase",
    "child-murders-parent",
    "cloning",
    "coercive-persuasion",
    "combat",
    "coming-of-age",
    "commander",
    "co-pilot",
    "courage",
    "crashed-starship",
    "crash-landing",
    "creature",
    "crisis-of-conscience",
    "crossbow",
    "crossguard-lightsaber",
    "damsel-in-distress",
    "danger",
    "death",
    "death-of-father",
    "death-of-friend",
    "death-of-hero",
    "deception",
    "desert",
    "deserter",
    "desert-landscape",
    "desert-planet",
    "destiny",
    "destruction",
    "destruction-of-planet",
    "detonator",
    "dogfight",
    "double-cross",
    "droid",
    "duel",
    "eaten-alive",
    "electrocution",
    "elevator",
    "epic",
    "epic-battle",
    "escape",
    "exploding-building",
    "exploding-planet",
    "exploding-ship",
    "explosion",
    "explosive",
    "face-slap",
    "falling-from-height",
    "family-drama",
    "famous-score",
    "father-and-son",
    "father-son-relationship",
    "fear",
    "female-fighter",
    "female-general",
    "female-hero",
    "female-pilot",
    "female-protagonist",
    "female-soldier",
    "female-spy",
    "female-starfighter-pilot",
    "female-warrior",
    "fictional-planet",
    "fictional-war",
    "fight",
    "fighter-pilot",
    "film-starts-with-text",
    "fire",
    "fistfight",
    "five-word-title",
    "flamethrower",
    "flame-thrower",
    "flight-helmet",
    "food-shortage",
    "foot-chase",
    "forest",
    "f-rated",
    "fugitive",
    "gang",
    "general",
    "genetic-engineering",
    "giant",
    "goggles",
    "good-versus-evil",
    "gun",
    "gunfight",
    "handheld-detonator",
    "hand-to-hand-combat",
    "hatred",
    "hearing-voices",
    "heavy-rain",
    "held-at-gunpoint",
    "helmet",
    "henchman",
    "hologram",
    "hope",
    "hostage",
    "human-in-outer-space",
    "humanoid-alien",
    "humanoid-robot",
    "humor",
    "hyperspace",
    "imax-version",
    "interrogation",
    "island",
    "jailbreak",
    "jedi",
    "jedi-knight",
    "junkyard",
    "key",
    "kidnapping",
    "knocked-out",
    "laser",
    "laser-cannon",
    "laser-gun",
    "lens-flare",
    "lieutenant",
    "lifting-person-in-air",
    "lightsaber",
    "lightsaber-battle",
    "long-take",
    "macguffin",
    "magical-power",
    "major",
    "male-female-hug",
    "man-with-no-name",
    "map",
    "martial-arts",
    "masked-man",
    "masked-villain",
    "massacre",
    "mass-murder",
    "megalomaniac",
    "mercilessness",
    "midget",
    "millennium-falcon",
    "mind-control",
    "mind-reading",
    "missing-person",
    "mission",
    "mixed-martial-arts",
    "mon-calamari",
    "monster",
    "mother-daughter-relationship",
    "murder",
    "near-death-experience",
    "no-opening-credits",
    "number-in-character\u0027s-name",
    "nurse",
    "obesity",
    "one-against-many",
    "one-man-army",
    "one-woman-army",
    "on-the-run",
    "open-ended",
    "opening-action-scene",
    "orphan",
    "outer-space",
    "outnumbered",
    "outpost",
    "patricide",
    "pilot",
    "planet",
    "planetary-destruction",
    "plasma",
    "power-outage",
    "presumed-dead",
    "prisoner",
    "prisoner-of-war",
    "produced-by-director",
    "prosthetic-limb",
    "protocol-droid",
    "punched-in-the-face",
    "quest",
    "quicksand",
    "r2-d2",
    "race-against-time",
    "rage",
    "rationing",
    "reboot",
    "red-blade-lightsaber",
    "redemption",
    "reluctant-hero",
    "remote-detonator",
    "rescue",
    "rescue-mission",
    "resistance",
    "resistance-fighter",
    "returning-character-killed-off",
    "revenge",
    "robot",
    "robotic-arm",
    "roman-numbered-sequel",
    "roman-numeral-in-title",
    "sabotage",
    "saga",
    "scavenger",
    "scavenging-for-parts",
    "science-fantasy",
    "scottish-accent",
    "scrap-dealer",
    "scrap-merchant",
    "sequel",
    "seventh-part",
    "seven-word-title",
    "shipwreck",
    "shooting",
    "shootout",
    "shot-in-the-arm",
    "shot-in-the-back",
    "shot-in-the-chest",
    "shot-in-the-head",
    "shot-in-the-shoulder",
    "shot-to-death",
    "showdown",
    "skull",
    "slow-motion-scene",
    "smuggler",
    "snow",
    "snowy-landscape",
    "soldier",
    "son-murders-father",
    "space-battle",
    "spacecraft",
    "spacecraft-cockpit",
    "space-fleet",
    "space-opera",
    "spaceship",
    "spaceship-crash",
    "spaceship-wreckage",
    "space-station",
    "space-travel",
    "space-western",
    "spear",
    "spit-take",
    "stabbed-in-the-chest",
    "stabbed-in-the-shoulder",
    "stabbed-through-the-chest",
    "star-destroyer",
    "starfighter",
    "starfighter-cockpit",
    "starfighter-pilot",
    "starfighter-pilot-helmet",
    "starship",
    "starship-bridge",
    "starship-wreckage",
    "star-wars",
    "stormtrooper",
    "strangulation",
    "strong-female-character",
    "strong-female-lead",
    "strong-woman",
    "stylized-violence",
    "subtitled-scene",
    "sun",
    "supernatural-power",
    "super-weapon",
    "surprise-ending",
    "survival",
    "sword-duel",
    "sword-fight",
    "talking-robot",
    "telekinesis",
    "telepathy",
    "tent",
    "tentacle",
    "tentacled-alien",
    "tentacled-creature",
    "the-force",
    "thirst",
    "tie-fighter",
    "torture",
    "tough-girl",
    "tough-guy",
    "turncoat",
    "unlikely-hero",
    "village",
    "violence",
    "violent-outburst",
    "vision",
    "walkie-talkie",
    "warp-speed",
    "warrior",
    "water",
    "weapon-of-mass-destruction",
    "wilhelm-scream",
    "winter",
    "wisecrack-humor",
    "woman",
    "woman-fights-a-man",
    "woman-hits-a-man",
    "woman-kills-a-man",
    "woman-punches-a-man",
    "woods",
    "wookie",
    "wookiee",
    "world-destruction",
    "world-domination",
    "written-by-director",
    "x-wing-starfighter"
  ],
  "languages": [
    {
      "language": "English"
    }
  ],
  "locations": [
    {
      "location": "1666 Euclid St, Santa Monica, California, USA",
      "note": "(Bad Robot Productions)"
    },
    {
      "location": "Abu Dhabi, United Arab Emirates"
    },
    {
      "location": "Derwentwater, Lake District, Cumbria, England, UK",
      "note": "(Approach to Maz Kanata\u0027s Castle, Takodana)"
    },
    {
      "location": "Greenham Common, England, UK",
      "note": "(landing docks)"
    },
    {
      "location": "Iceland",
      "note": "(Mývatn, Krafla volcano)"
    },
    {
      "location": "New Mexico, USA"
    },
    {
      "location": "Pinewood Studios, Iver Heath, Buckinghamshire, England, UK"
    },
    {
      "location": "Puzzle Wood, Perrygrove Road, Coleford, Forest of Dean, Gloucestershire, England, UK",
      "note": "(Forest on Takodana)"
    },
    {
      "location": "Scotland, UK"
    },
    {
      "location": "Skellig Michael, County Kerry, Ireland"
    }
  ],
  "release_dates": {
    "UK": [
      {
        "release_date": "2015-12-16",
        "note": "(London) (premiere)"
      },
      {
        "release_date": "2015-12-17"
      }
    ],
    "USA": [
      {
        "release_date": "2015-12-14",
        "note": "(Los Angeles, California) (premiere)"
      },
      {
        "release_date": "2015-12-18"
      }
    ],
    "Fiji": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Peru": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Chile": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "China": [
      {
        "release_date": "2015-12-29",
        "note": "(Beijing) (premiere)"
      },
      {
        "release_date": "2016-01-09"
      }
    ],
    "Egypt": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "India": [
      {
        "release_date": "2015-12-25"
      }
    ],
    "Italy": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Japan": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Nepal": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Spain": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Brazil": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Canada": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Cyprus": [
      {
        "release_date": "2015-12-25"
      }
    ],
    "France": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Greece": [
      {
        "release_date": "2015-12-17",
        "note": "(Athens) (premiere)"
      },
      {
        "release_date": "2015-12-24"
      }
    ],
    "Israel": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Kuwait": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Latvia": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Mexico": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Norway": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Poland": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Russia": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Serbia": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Sweden": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Taiwan": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Turkey": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Armenia": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Austria": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Bahrain": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Belarus": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Belgium": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Bolivia": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Croatia": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Denmark": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Estonia": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Finland": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Germany": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Hungary": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Iceland": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Ireland": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Lebanon": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Morocco": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Romania": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Tunisia": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Ukraine": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Uruguay": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Vietnam": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Bulgaria": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Cambodia": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Colombia": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Malaysia": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Pakistan": [
      {
        "release_date": "2015-12-25"
      }
    ],
    "Portugal": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Slovakia": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Slovenia": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Thailand": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Argentina": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Australia": [
      {
        "release_date": "2015-12-16",
        "note": "(Sydney) (Premiere)"
      },
      {
        "release_date": "2015-12-17"
      }
    ],
    "Guatemala": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Hong Kong": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Indonesia": [
      {
        "release_date": "2015-12-15",
        "note": "(Jakarta) (premiere)"
      },
      {
        "release_date": "2015-12-18"
      }
    ],
    "Lithuania": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Singapore": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Sri Lanka": [
      {
        "release_date": "2015-12-25",
        "note": "(Colombo) (premiere)"
      }
    ],
    "Venezuela": [
      {
        "release_date": "2015-12-18"
      }
    ],
    "Azerbaijan": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Bangladesh": [
      {
        "release_date": "2015-12-25"
      }
    ],
    "Kazakhstan": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Luxembourg": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Netherlands": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "New Zealand": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Philippines": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "South Korea": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Switzerland": [
      {
        "release_date": "2015-12-16",
        "note": "(French speaking region)"
      },
      {
        "release_date": "2015-12-16",
        "note": "(Italian speaking region)"
      },
      {
        "release_date": "2015-12-17",
        "note": "(German speaking region)"
      }
    ],
    "South Africa": [
      {
        "release_date": "2015-12-16"
      }
    ],
    "Czech Republic": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Dominican Republic": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "United Arab Emirates": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Republic of Macedonia": [
      {
        "release_date": "2015-12-17"
      }
    ],
    "Bosnia and Herzegovina": [
      {
        "release_date": "2015-12-17"
      }
    ]
  }
}

Looking up a person by ID

In a similar way we can extact a GetPersonById.java by ID:

import uk.ac.cam.cl.databases.moviedb.MovieDB;
import uk.ac.cam.cl.databases.moviedb.model.*;

public class GetPersonById {
    public static void main(String[] args) {
        try (MovieDB database = MovieDB.open(args[0])) {
            int id = Integer.parseInt(args[1]);
            Person person = database.getPersonById(id);
            System.out.println(person);
        }
    }
}

Put this code in a file called GetPersonById.java in the same directory as the jar file you downloaded. You can then compile and run the example as follows (if you are running Microsoft Windows):

# On Windows
javac -classpath document-db.jar GetPersonById.java
java -classpath .;document-db.jar GetPersonById document-movie-db 121299

If you are running Linux or Mac OS, the commands are very similar -- you just need to replace the semicolon with a colon in the second command:

# On Linux or Mac OS
javac -classpath document-db.jar GetPersonById.java
java -classpath .:document-db.jar GetPersonById document-movie-db 121299

When you run the program, the output should look like this:

{
  "id": 121299,
  "name": "Bacon, Kevin (I)",
  "gender": "male",
  "actor_in": [
    {
      "character": "Jack Brennan",
      "position": 4,
      "movie_id": 3519211,
      "title": "Frost/Nixon (2008)"
    }
  ]
}

Scanning all movies, people

You can also search the database by the name of a person who is credited on a movie (whether as actor, director, producer or some other role). The name is stored in the form surname, firstname. For example, you can look up Daniel Radcliffe like this:

database.getByNamePrefix("Radcliffe, Daniel")

The result of getByNamePrefix is a sequence of Person objects. Below we will look at methods for accessing elements of such an object. But first, we will use the getByNamePrefix to scan over all people like this:

database.getByNamePrefix("")

The following code simply counts the number of people in the selected database:

import uk.ac.cam.cl.databases.moviedb.MovieDB;
import uk.ac.cam.cl.databases.moviedb.model.*;

public class CountPeople {
    public static void main(String[] args) {
        int count = 0;
        try (MovieDB database = MovieDB.open(args[0])) {
            for (Person person : database.getByNamePrefix("")) {
                count++;
            }
            System.out.println("Number of people: " + count);
        }
    }
}

With our database (document-movie-db), this should return:

Number of people: 9283

In a similar way we can scan over all movies by using the getByTitlePrefix method. The following code counts all movies in the selected database:

import uk.ac.cam.cl.databases.moviedb.MovieDB;
import uk.ac.cam.cl.databases.moviedb.model.*;

public class CountMovies {
    public static void main(String[] args) {
        int count = 0;
        try (MovieDB database = MovieDB.open(args[0])) {
            for (Movie movie : database.getByTitlePrefix("")) {
                count++;
            }
            System.out.println("Number of movies: " + count);
        }
    }
}

This should return:

Number of movies: 120

Searching by Title

How do you find a movie if you don't already know its ID? Let's search by title instead. You can use database.getByTitlePrefix, and loop over the matching movies. Note that the search only looks at the beginning of the title (not words in the middle of the title), and it is case-sensitive. For example, the following program looks up the ID and title of all movies whose title starts with Harry Potter and the:

import uk.ac.cam.cl.databases.moviedb.MovieDB;
import uk.ac.cam.cl.databases.moviedb.model.*;

public class MoviesByTitle {
    public static void main(String[] args) {
        try (MovieDB database = MovieDB.open(args[0])) {
            System.out.println("List of Harry Potter movies:");

            // Search for movies whose title starts with some string
            for (Movie movie : database.getByTitlePrefix("Harry Potter and the ")) {
                System.out.println("    " + movie.getId() + ": " + movie.getTitle());
            }
        }
    }
}

Note that this code uses method calls movie.getId() and movie.getTitle(). These and many other methods are described here: Java documentation.

The code above will produce this output on document-movie-db:

List of Harry Potter movies:
    3571970: Harry Potter and the Deathly Hallows: Part 2 (2011)

Change the query to search for your favourite movie, and print the results. The database contains only 120 movies from the last 12 years, so your favourite one might not be included.

Searching for an actor's roles

List the titles of all the movies in which Matt Damon played, and the name of the character he played in each:

import uk.ac.cam.cl.databases.moviedb.MovieDB;
import uk.ac.cam.cl.databases.moviedb.model.*;

public class MoviesByActor {
    public static void main(String[] args) {
        try (MovieDB database = MovieDB.open(args[0])) {
            for (Person person : database.getByNamePrefix("Damon, Matt")) {
                System.out.println(person.getName() + " played:");
                for (Role role : person.getActorIn()) {
                    System.out.println("    " + role.getCharacter() + " in " + role.getTitle());
                }
            }
        }
    }
}

The output should look like this:

Damon, Matt played:
    Colin Sullivan in The Departed (2006)
    Jason Bourne in The Bourne Ultimatum (2007)
    Himself - Narrator in Inside Job (2010)
    LaBoeuf in True Grit (2010)
    Mark Watney in The Martian (2015)

Genres of movies in which an actor has played

You may have noticed in the documentation that a Movie object has a getGenres() method, which returns a list of genre names that characterise the movie. Let's say you want to show a summary of the kinds of movies in which a particular actor tends to play.

We now write a program that looks up an actor by name, finds all the movies in which they have played, and then counts the number of movies by genre. Since a movie can have more than one genre, each movie may be counted several times – that's ok. Given the name of an actor, find all the movies in which they have played, and then count the number of movies by genre. A movie with multiple genres may be counted multiple times.

Notes: A person object has a list of Role objects representing the movies in which that person has played. The role object has the title and ID of the movie, but no other details about the movie – in particular, not the genre. Thus, the genres need to be looked up separately by querying the database by movie ID. This is an example of a join in Java!

Here is the code:

import java.util.Map;
import java.util.TreeMap;
import uk.ac.cam.cl.databases.moviedb.MovieDB;
import uk.ac.cam.cl.databases.moviedb.model.*;

public class GenresByActor {
    public static void main(String[] args) {
        try (MovieDB database = MovieDB.open(args[0])) {
            for (Person person : database.getByNamePrefix("Damon, Matt")) {
                TreeMap<String, Integer> genreCount = new TreeMap<>();

                for (Role role : person.getActorIn()) {
                    // Perform a join by looking up the ID of the movie
                    Movie movie = database.getMovieById(role.getMovieId());

                    // Iterate over the genres of that movie, and add them to the map
                    if (movie.getGenres() != null) {
                        for (String genre : movie.getGenres()) {
                            if (genreCount.containsKey(genre)) {
                                genreCount.put(genre, genreCount.get(genre) + 1);
                            } else {
                                genreCount.put(genre, 1);
                            }
                        }
                    }
                }

                // Print out the aggregate counts
                System.out.println(person.getName() + " appears in movies of the following genres:");
                for (Map.Entry<String, Integer> count : genreCount.entrySet()) {
                    System.out.println("    " + count.getKey() + ": " + count.getValue() + " movies");
                }
            }
        }
    }
}

The output should look like this:

Damon, Matt appears in movies of the following genres:
    Action: 1 movies
    Adventure: 2 movies
    Crime: 2 movies
    Documentary: 1 movies
    Drama: 3 movies
    Mystery: 1 movies
    Sci-Fi: 1 movies
    Thriller: 2 movies
    Western: 1 movies

Practical Exercises (ticks) from 2016

Recall the relational Exercise 1.c in which you searched for pairs of actors who share the top billing of a movie. Let's implement the same thing using the document database.

As usual, the program should take the path to the database directory as the first command-line argument. The second command-line argument should be a number, namely the position to search for. If that number is x, we search for two actors who both have position x on the same movie.

Fill in the following template:

import uk.ac.cam.cl.databases.moviedb.MovieDB;
import uk.ac.cam.cl.databases.moviedb.model.*;

public class Exercise3 {
    public static void main(String[] args) {
        try (MovieDB database = MovieDB.open(args[0])) {
            int requiredPosition = Integer.parseInt(args[1]);
            // YOUR CODE GOES HERE
        }
    }
}

You should be able to compile and run it as usual:

# On Windows
javac -classpath document-db.jar Exercise3.java
java -classpath .;document-db.jar Exercise3 document-small 1

# On Linux or Mac OS
javac -classpath document-db.jar Exercise3.java
java -classpath .:document-db.jar Exercise3 document-small 1

With the number 1 as position argument (as in the command line above) it should produce the following output:

Owen, Clive (I) and Yacuzzi, Juan Gabriel both have position 1 in Children of Men (2006)

If you change number 1 to 4, it should produce the following output:

Chevalier, Jon and Moore, Julianne both have position 4 in Children of Men (2006)
Batey, Toya and Williams, Cobe both have position 4 in The Interrupters (2011)

The actor names should appear in alphabetical order.

Solution notes

Here is one possible solution:

import uk.ac.cam.cl.databases.moviedb.MovieDB;
import uk.ac.cam.cl.databases.moviedb.model.*;

public class Exercise3 {
    public static void main(String[] args) {
        try (MovieDB database = MovieDB.open(args[0])) {
            int requiredPosition = Integer.parseInt(args[1]);

            // Scan over all movies
            for (Movie movie : database.getByTitlePrefix("")) {
                // Keeps track of the name of an actor with the required
                // position in the current movie
                String firstMatch = null, secondMatch = null;

                for (CreditActor actor : movie.getActors()) {
                    // The null check is required because some actors have a
                    // null position, and you get a NullPointerException due to
                    // auto-unboxing if you just compare getPosition() == int
                    if (actor.getPosition() != null && actor.getPosition() == requiredPosition) {
                        if (firstMatch == null) {
                            firstMatch = actor.getName();
                        } else {
                            // We have found two actors with the required position.
                            // Now order their names lexicographically.
                            if (firstMatch.compareTo(actor.getName()) < 0) {
                                secondMatch = actor.getName();
                            } else {
                                secondMatch = firstMatch;
                                firstMatch = actor.getName();
                            }

                            System.out.println(firstMatch + " and " + secondMatch +
                                " both have position " + requiredPosition + " in " +
                                movie.getTitle());
                        }
                    }
                }
            }
        }
    }
}