View Source How To

store-multiple-collections

Store multiple collections

The ability of CubDB to retrieve ranges of data sorted by key makes it ideal to store sorted collections, sort of like tables in a relational database. Different collections can be stored in the same database, or in separate ones.

The main reason to use separate CubDB databases is if you need different configuration options for each database (like auto compaction or file sync).

Otherwise, it is usually simpler and more efficient to use a single database: read operations in CubDB execute concurrently, and while write operations on the same database are serialized, using multiple databases means losing the advantage of the append-only nature of CubDB, resulting in often slower patterns of file access.

One common way to store separate collections in the same database is to use composite keys, usually tuples, leveraging the fact that the Erlang runtime defines a total ordering of all terms.

Say that you want to store two collections: people and articles. You can structure your keys to be tuples like {:people, person_id} for people, and {:articles, article_id} for articles:

# Add a few people:
:ok = CubDB.put(db, {:people, 1}, %{first_name: "Margaret", last_name: "Hamilton"})
:ok = CubDB.put(db, {:people, 2}, %{first_name: "Alan", last_name: "Turing"})

# Add a few articles:
:ok = CubDB.put(db, {:articles, 1}, %{title: "Spaceship Guidance made easy", text: "..."})
:ok = CubDB.put(db, {:articles, 2}, %{title: "Morphogenesis for the uninitiated", text: "..."})

We used positive integers as IDs in our example, but you can really use anything you want.

Getting a specific person or article by ID is trivial:

person = CubDB.get(db, {:people, 1})

article = CubDB.get(db, {:articles, 2})

Selecting all members of a collection without selecting also other collections can be easily done by leveraging the fact that tuples are compared element by element. Therefore, here is how you can select all members of a specific collection:

# Select all people
{:ok, people_wth_keys} = CubDB.select(db, min_key: {:people, 0}, max_key: {:people, nil})

# Select all articles
{:ok, articles_with_keys} = CubDB.select(db, min_key: {:articles, 0}, max_key: {:articles, nil})

This range selection works because our IDs are positive integers, and nil is greater than all numbers, so {:abc, nil} is greater than {:abc, 123}, but smaller than {:bcd, :123}.

save-and-restore-a-backup

Save and restore a backup

Use the CubDB.back_up/2 function to create a backup of the current state of the database. Once the backup is completed, it can be opened by starting a new CubDB process using the target directory of the backup as its data directory:

# Backup the current state of the database
:ok = CubDB.back_up(db, "some/target/path")

# Open the backup as another CubDB process
{:ok, copy} = CubDB.start_link(data_dir: "some/target/path")