LMU ☀️ CMSI 3520
DATABASE SYSTEMS
Final Exam Answers
  1. The surprise problem:
    1. Mongo is a document database.
    2. Postgres is a relational database.
    3. Neo is a graph database.
    4. Redis is a key-value database.
    5. Sarah Mei thinks you should never use Mongo.
    6. Redis (and similar) databases make really good caches.
    7. ACID stands for atomicity consistency isolation durability.
    8. Mongo doesn’t have joins because it favors horizontal scaling.
    9. If you use promises, you don’t need callbacks (T/F): F.
    10. Databases with schemas generally mean you must suffer with migrations.
  2. Mongo.
    db.movies.insertOne({
      title: 'The Incredibles', year: 2004, studio: 'Pixar',
      directors: [{name: 'Brad Bird', birthdate: new Date('1957-09-24')}],
      actors: [
        {name: 'Holly Hunter', birthdate: new Date('1958-03-20'), roles: ['Elastigirl', 'Helen Parr']},
        {name: 'Samuel L. Jackson', roles: ['Lucius Best', 'Frozone']},
        {name: 'Sarah Vowell', roles: ['Violet Parr']}
      ]
    });
    
    // Titles and studios for sequels with actors born before 1940
    db.movies.find(
      {'actors.birthdate': {$lt: new Date('1940')}, sequel_of: {$exists: 0}},
      {_id: 0, title: 1, studio: 1}
    );
    
    // Names of directors that directed a movie made in 2000
    db.movies.find({year: 2000}, {'_id': 0, 'directors.name': 1});
    
    // Names of all Pixar movies that John Ratzenberger starred in,
    // together with the roles he played in each, sorted by movie
    // release year, most recent first
    db.movies.aggregate([
      {$match: {studio: 'Pixar', 'actors.name': {$eq: 'John Ratzenberger'}}},
      {$project: {_id: 0, title: 1, 'actors.roles': 1, year: 1}},
      {$sort: {year: -1}},
      {$project: {_id: 0, title: 1, 'actors.roles': 1}}
    ]);
    
  3. Postgres. We don’t need a separate table for the sequel relationship because it is one-to-many and not many-to-many. We can just use a nullable column in the movie table to indicate which movie it is a sequel of, if any.
    create table person (
      id serial primary key not null,
      name varchar not null,
      birthdate date,
      headshot_url varchar
    );
    create table movie (
      id serial primary key not null,
      title varchar not null,
      year int,
      studio varchar,
      sequel_of int references movie (id)
    );
    create table director (
      person_id int not null,
      movie_id int not null,
      primary key (person_id, movie_id),
      foreign key (person_id) references person (id),
      foreign key (movie_id) references movie (id)
    );
    create table actor (
      person_id int not null,
      movie_id int not null,
      roles jsonb,
      primary key (person_id, movie_id),
      foreign key (person_id) references person (id),
      foreign key (movie_id) references movie (id)
    );
    
    -- Title and studio for non-sequels with actors born before 1940
    select distinct m.title, m.studio
    from movie m
    join actor a on m.id = a.movie_id
    join person p on p.id = a.person_id
    where m.sequel_of is null
    and p.birthdate < '1940-01-01';
    
    -- For each director, the number of movies he or she directed,
    -- ordered by the number of movies descending.
    select p.name, count(d.movie_id) as number_of_movies
    from person p
    join director d on p.id = d.person_id
    group by p.name
    order by 2 desc;
    
    -- Names of all Pixar movies that John Ratzenberger starred in,
    -- together with the roles he played in, sorted by movie release
    -- year, most recent first.
    select m.title, a.roles
    from person p
    join actor a on p.id = a.person_id
    join movie m on a.movie_id = m.id
    where p.name = 'John Ratzenberger'
    and m.studio = 'Pixar'
    order by m.year desc;
    
  4. Neo.
    create (incredibles:Movie {title: 'The Incredibles', studio: 'Pixar', year: '2004'}),
           (cars:Movie {title: 'Cars', studio: 'Pixar', year: '2006'}),
           (cars2:Movie {title: 'Cars 2', studio: 'Pixar', year: '2011'}),
           (hh:Person {name: 'Holly Hunter', birthday: '19580320'}),
           (jr:Person {name: 'John Ratzenberger', birthday: '19470406'}),
           (hh)-[:ACTED_IN {roles: ['Elastigirl', 'Helen Parr']}]->(incredibles),
           (jr)-[:ACTED_IN {roles: ['The Underminer']}]->(incredibles),
           (jr)-[:ACTED_IN {roles: ['Mack']}]->(cars),
           (jr)-[:ACTED_IN {roles: ['Mack', 'Hamm Tuck']}]->(cars2),
           (cars2)-[:SEQUEL_OF]->(cars);
    
    // Title and studio for non-sequels with actors born before 1940.
    match (m:Movie)<-[:ACTED_IN]-(p:Person)
    where p.birthday < '19400101'
    and not exists ((m)-[:SEQUEL_OF]->(:Movie))
    return distinct m.title, m.studio;
    
    // For each director, the number of movies he or she directed,
    // ordered by the number of movies descending.
    match (p:Person)-[:DIRECTED]->(m:Movie)
    return p.name as director, count(*) as number_of_movies_directed
    order by number_of_movies_directed desc;
    
    // Names of all Pixar movies that John Ratzenberger starred in,
    // together with the roles he played in each, sorted by movie
    // release year, most recent first.
    match (p:Person {name: 'John Ratzenberger'})-[a:ACTED_IN]->(m:Movie {studio: 'Pixar'})
    return m.title, m.year, a.roles
    order by m.year desc;
    
    // Titles of all movies that were sequels of sequels of sequels.
    match (m:Movie)-[:SEQUEL_OF*3]->(:Movie)
    return m.title;
    
  5. Redis.
    hmset m:the-incredibles title "The Incredibles" studio "Pixar" year 2004
    
    hmset p:holly-hunter name "Holly Hunter" birthdate "1958-03-20"
    hset p:sarah-vowell name "Sarah Vowell"
    hmset p:brad-bird name "Brad Bird" birthdate "1957-09-24"
    
    lpush m:the-incredibles:p:holly-hunter "Helen Parr" "Elastigirl"
    lpush m:the-incredibles:p:holly-hunter
    sadd m:the-incredibles:d "p:brad-bird"
    
    scard m:the-prestige:d
    
    exists m:gone-with-the-wind:p:hugh-jackman
    
    hset m:the-circle year 2017
    
    zrevrangebyscore rt-scores +inf -inf limit 0 5
    /* OR */
    zrevrange rt-scores 0 4 withscores
    
  6. In a Sequelize application, it’s super annoying that you have to hand-code migrations for join tables in a many-to-many relationship. Regular tables can be pretty much auto-generated, but not the join tables (as far as we were able to tell).