Data Modeling

Lessons

Terms

  • Data: Strings, booleans, numbers, arrays and objects.
  • Model: A way of representing something as data.
  • Instance: A single representation of something as using a model. For our purposes, this will be an object.
  • Factory function: A function that outputs instances of a model.

Exercises

Basic Requirements

Representing Books

  1. Think about some different attributes of books – what do all books have? Ideas include:

    • Title
    • Author
    • MSRP
    • Genre
    • Number of Pages
    • Description
  2. In terms of the properties of books that you thought of, represent the following books as data:

    • Harry Potter and the Sorcerer's Stone (J.K. Rowling)
    • Snow Crash (Neal Stephenson)
    • Structure and Interpretation of Computer Programs (Gerald Jay Sussman, Hal Abelson)
      • NOTE: Did you account for the possibility of two authors? If not, update your model to handle multiple authors.
    • Three other books (see this list for ideas)
  3. You have probably had to rewrite the same kind of object multiple times at this point; write a function makeBook that takes as arguments different aspects of a book and returns an object representing that book that has the proper structure (we call this a factory function).

Formatting

Look at one of your book objects in the console. The object inspector is nice, but it would be nice if we could easily view important attributes of a book without having to click on all of its properties with the inspector. Write a function called displayBook that takes a book as an argument, and "pretty prints" the important parts, for example:

var sorcerersStone = { /* ... */ }
          function displayBook(book) {
          // ...
          }
          displayBook(sorcerersStone);
          // => "Harry Potter and the Sorcerer's Stone, by J.K. Rowling -- fantasy, $24.99"
          

The output string above is only an example – the idea is that, given a book object, displayBook returns some string that shows some subset of the information about the book that is deemed important – what is shown is up to you.

Handling Multiple Books

  1. If you haven't already, create an array to hold all of the books that you created above called books.

  2. You have written the function displayBook that can be used to display a single book as a string – write a function displayBooks that, given an array of books, returns a single string consisting of all of the books formatted using the displayBook function you defined before.

    Each book should be numbered, and separated with a newline character so that each book is shown on a separate line in the console. The newline character is specified with a special escaped character in a string:

    // Enter the below line into a console
              "Hello\nWorld!"; // the \n character is a newline
              function displayBooks(books) {
                // ...
              }
              displayBooks(books);
              // => "1. Harry Potter and the Sorcerer's Stone...\n2. Snow Crash, ..."
              
  3. Write a function searchBooks that, given a query and an array of books, searches the array of books for "matching" books. You'll need to make a few decisions when implementing a search algorithm, like:

    • What fields will be searched? Will you search multiple fields simultaneously (it might be best to start with one field, e.g. title)? Should the search be case-sensitive?

    • How will the search work? Will it only work from the beginning of a field, or from anywhere within?

      A good starting point would be to write a function isMatch that accepts two arguments – the query and a single book – and returns true if the book is a match, and false otherwise. Some Hints:

      "Harry Potter".toLowerCase(); // => "harry potter"
                "Harry Potter".substr(0, 5); // => "Harry"
                var query = "Harry";
                "Harry Potter".substr(0, query.length); // => "Harry"
                "Harry Potter".indexOf("Pot"); // => 6
                "Harry Potter".indexOf("dog"); // => -1
                
  4. Write a function removeBook that, given a book's title and an array of books, returns a new array of books that does not contain the book with the provided title.

More Practice: Representing Movies

  1. As we did before, think about what kinds of aspects of movies you would like to represent. A few ideas are:

    • Title
    • Director
    • Duration
    • Release Date
    • Actors/Actresses
    • Studio(s)
    • Synopsis
    • Rating

    The level of granularity with some of these values is up for you to decide; for instance, the actors/actresses could be represented with an array of names, but what if you wanted to include the role that the actor/actress played? Did he/she win any awards? Even the rating of a movie is open to interpretation – is the rating from critics? Users of IMDB? Rotten Tomatoes? Some combination?

  2. Using the format that you decide upon, construct five movie objects.

  3. Write a factory function for movies.

  4. Write a function displayMovie that works like displayBook, but for movies.

  5. Write a function displayCast that displays the cast of a movie, including:

    • Role
    • Actor/Actress name
  6. Create an array to hold the movies that you created called movies, and add your movies to it.

  7. As before, write a displayMovies function that works just like displayBooks.

  8. Calculate the average duration of your movies by writing a function called averageDuration that will accept an array of movies as a parameter and ouput the average duration. The difficulty of this problem is dependent on how you have chosen to store the duration.

    • How about averageRating?
  9. How about searching your movies array? Write a function that works like searchBooks, but for movies.

Advanced

  1. Tagging System: Some books have multiple genres, have won awards, are on a best-seller list, or have other unique identifying characteristics. Let's incorporate a tagging system that will allow us to represent all of these. Write functions addTag and removeTag that each accept a book and a tag as parameters, and either add tags or remove tags respectively. Considerations:

    • If you included a genre key, replace it with a tag.
    • What if you use addTag on a book that has no tags yet?
    • What if you attempt to use addTag with the same tag (on the same book) multiple times? Should it be possible to have the same tag twice?
    • Add some tags to multiple books, like "bestseller" or "pulitzer".
    • Extend
    • Extend searchBooks to work with tags.
  2. Let's revisit your removeBooks function: what would happen if you had two books with the same title, but different authors? Would your algorithm remove both books? This is a common problem that we usually solve by providing a unique identifier for each item.

    • Modify all of your books to contain an id key with a unique value. This can be an integer or a unique string (like an ISBN).
    • Change removeBook to use the book's id for lookups instead of its title.
  3. Can you think of a way to write a more abstract displayItem function that works for books and movies (depending on how you have structured your objects, this may or may not work well)?

  4. Write a more general searchItems function that accepts as parameters the query, items to search, and an array of keys that should be searched. Refactor searchMovies and searchBooks to use this function.