Skip to content

Walkthrough: Personal Media Library

In this walkthrough, we will build a personal media library.

Goal: The goal of this is not to build an amazing app, but rather to demonstrate one way that you can store data in golem-base, and build an app around that data movel. Note also that this is just one way of many.

This library will have some basic features. You will be able to:

  • Store entries of type Book, Movie, or Music.
  • Load the library with a sample data set
  • Add a new entry
  • Edit any single entry
  • Delete any single entry
  • Delete all the data
  • Query for entities using a unique query form that prepopulates dropdowns based on existing options in the data

But unlike a traditional app such as this, it will store its data in a golem-base op-geth node. Each media item will be stored as a single entity.

The approach we're taking is that we'll be modeling the equivalent of three SQL tables with rows and columns. But to store the data as entities rather than as tables, we'll instead take each column:value pair and store it as an entity with column as the key along with the value.

So, for example, one such column is called genre, and it holds a string. Suppose genre in one row is "sci-fi". In that case, for storing in Golem-base, we would include a string entity with

  • key: genre

  • value: sci-fi

Note: While in this app we're modeling three SQL tables, in fact each media item is simply stored as an entity. But to help model them as tables, we're including a field called "type" that denotes the "table"; it can hold either "book", "movie", or "music". From there we're maintaining a consistent schema within each book, movie, and music entity.

Fields

Although we're free to use whatever string annotations we want, we're maintaining consistency between types. All books have the same fields; all movies have the same fields; and all music items have the same fields.

Additionally, each entity has a field called "app". The purpose of this field is to hold a unique value there so that we can easily search for all entities in the app. Ideally this should be unique across all entities stored in the golem-base node. Additionally, we're including a version number to help distinguish the items from earlier versions (and so we can delete all earlier versions of data by simply searching for entities that contain that version.)

Most of these fields should be self explanatory based on the name of the field..

Book Fields

  • type: "book". For book entities, this is always the same value, 'book'.

  • title: string

  • description: string

  • author: string

  • genre: string

  • rating: number. This is a rating from 1 to 10.

  • owned: boolean. Note: Golem-base only supports two data types, string and number. This field, therefore, is stored as a string: 'true' or 'false'.

  • year: number.

Movie Fields

  • type: "movie". For movie entities, this is always the same value, 'movie'.

  • title: string

  • description: string

  • director: string

  • genre: string

  • rating: number. This is a rating from 1 to 10.

  • watched: boolean. Note: Golem-base only supports two data types, string and number. This field, therefore, is stored as a string: 'true' or 'false'.

  • year: number

Music Fields

  • type: "music";

  • title: string;

  • description: string;

  • artist: string;

  • genre: string;

  • rating: number;

  • favorite: boolean;

  • year: number;

Each entity also have an app field, which is not actually used by the front end application, but rather internally to idenfity the entities as belonging to this app.

Tip: If you want to enhance this app, try adding a "user" field that stores a user ID. Then in the backend, store it automatically with each new entity, and include it in the query. Do not expose this field to the front end of the app; otherwise people could easily hack it by setting it to some other user's ID.

The Index ("searches" entity)

We also maintain and index entity that keeps track of all authors, directors, artists, and separate genres for books, movies, and music.

By the time the entity reaches the front end, it has a structure like the following:


    "directors": [
        "Christopher Nolan",
        "Denis Villeneuve",
        "Terry Gilliam"
    ],
    "artists": [
        "Pink Floyd",
        "Rush",
        "Yes"
    ],
    "authors": [
        "George R. R. Martin",
        "Neal Stephenson",
        "William Gibson"
    ],
    "movie_genres": [
        "dystopian",
        "sci-fi",
        "thriller"
    ],
    "music_genres": [
        "folk",
        "prog rock",
        "synthwave"
    ],
    "book_genres": [
        "cyberpunk",
        "fantasy"
    ]
}

But internally we decided to take a different approach from the earlier way of modeling SQL tables and instead store each list as a comma-separated list inside a string annotation like so:

  • key: "directors", value: "Christopher Nolan,Denis Villeneuve,Terry Gilliam"

  • key: "artists", value: "Pink Floyd,Rush,Yes"

  • key: "authors", value: "George R. R. Martin,Neal Stephenson,William Gibson"

  • key: "movie_genres", value: "dystopian,sci-fi,thriller"

  • key: "music_genres", value: "folk,prog rock,synthwave"

  • key: "book_genres", value: "cyberpunk,fantasy"

The above are all stored in a single entity as a set of string annotations. The entity includes a "type" string entity set to the value "searches" along with the usual app entity.

On the back end, as the user creates a new entity, we update the searches entity to include any new data for author, director, artist, or respective genre.

What do we use this for

Technically we don't really need this, but we wanted to prepopulate our dropdowns for the query with the existing values.

We also wanted to demonstrate how you can read and update an entity in realtime.

Let's build it!

Ready to go? Let's build it!

Head to Step 1.