databasedatabase-designnosqlschema

Schema for music lists + playlists web app


Assuming that all playlists are subsets of a user's main library of music, how should a main library as well as playlists be managed in the database? It seems like a playlists table would grow extremely quickly for even a moderate amount of users. Would this be a decent use case for a nosql database having a list of playlists in each User collection, as opposed to a giant playlists table incorporating all users in the same place?


Solution

  • A relational database is perfect for this problem and though you might end up with millions of records in the playlists and playlists_songs tables any modern RDBMS should be able to handle that with no problems.

    You may or may not need/want a table for albums, I've included it here for the sake of completeness...

    albums
        id          unsigned int(P)
        artist_id   unsigned int(F artists.id)
        name        varchar(50)
        ...
    
    +----+-----------+-----------------------------------+-----+
    | id | artist_id | name                              | ... |
    +----+-----------+-----------------------------------+-----+
    |  1 |         1 | The Last in Line                  | ... |
    |  2 |         3 | American IV: The Man Comes Around | ... |
    |  3 |         2 | Animal House Soundtrack           | ... |
    |  4 |         4 | None or Unknown                   | ... |
    | .. | ......... | ................................. | ... |
    +----+-----------+-----------------------------------+-----+
    

    Like albums, you may or may not want a table for artists but I've included it in case you want to show that kind of data.

    artists
        id              unsigned int(P)
        name            varchar(50)
        ...
    
    +----+-------------+
    | id | name        |
    +----+-------------+
    |  1 | Dio         |
    |  2 | Various     |
    |  3 | Johnny Cash |
    |  4 | Unknown     |
    |  5 | Sam Cooke   |
    | .. | ........... |
    +----+-------------+
    

    playlists is basic: a user can have an unlimited number of them and they have a name. In my example data we see that bob has two playlists "Mix" and "Speeches" while mary has only one "Oldies".

    playlists
        id          unsigned int(P)
        user_id     unsigned int(F users.id)
        name        varchar(50)
    
    +----+---------+----------+
    | id | user_id | name     |
    +----+---------+----------+
    |  1 |       1 | Mix      |
    |  2 |       1 | Speeches |
    |  3 |       2 | Oldies   |
    | .. | ....... | ........ |
    +----+---------+----------+
    

    We have to keep track of what songs are on each playlist. In my example data you can see that "Egypt (The Chains Are On)" and "Hurt" are on the "Mix" playlist while the "Town Hall speech" is on the "Speeches" playlist and "Egypt (The Chains Are On)", "Hurt" and "Twistin' the Night Away" are all on the "Oldies" playlist.

    playlists_songs
        id              unsigned int(P)
        playlist_id     unsigned int(F playlists.id)
        song_id         unsigned int(F songs.id)
    
    +----+-------------+---------+
    | id | playlist_id | song_id |
    +----+-------------+---------+
    |  1 |           1 |       1 |
    |  2 |           1 |       2 |
    |  3 |           2 |       4 |
    |  4 |           3 |       1 |
    |  5 |           3 |       2 |
    |  6 |           3 |       3 |
    | .. | ........... | ....... |
    +----+-------------+---------+
    

    Even though millions of users might all have the song "Hurt" in their collection, we only need to store information about each song once. So in the songs table we store information about each song including where the actual audio file is located. My example for file locations are just off the top of my head, how you would actually organize the files in the filesystem could easily be very different.

    songs
        id              unsigned int(P)
        album_id        unsigned int(F albums.id) // Default NULL
        artist_id       unsigned int(F artists.id)
        name            varchar(50)
        filename        varchar(255)
        ...
    
    +----+----------+-----------+---------------------------+---------------------------+-----+
    | id | album_id | artist_id | name                      | filename                  | ... |
    +----+----------+-----------+---------------------------+---------------------------+-----+
    |  1 |        1 |         1 | Egypt (The Chains Are On) | /media/audio/1/1/9.mp3    | ... |
    |  2 |        2 |         3 | Hurt                      | /media/audio/3/2/2.mp3    | ... |
    |  3 |        3 |         5 | Twistin' the Night Away   | /media/audio/5/2/3.mp3    | ... |
    |  4 |     NULL |         4 | Town Hall speech          | /media/audio/4/4/<id>.mp3 | ... |
    | .. | ........ | ......... | ......................... | ......................... | ... |
    +----+----------+-----------+---------------------------+---------------------------+-----+
    

    And of course your users table.

    users
        id              unsigned int(P)
        username        varchar(32)
        password        varbinary(255)
        ...
    
    +----+----------+----------+-----+
    | id | username | password | ... |
    +----+----------+----------+-----+
    |  1 | bob      | ******** | ... |
    |  2 | mary     | ******** | ... |
    | .. | ........ | ........ | ... |
    +----+----------+----------+-----+