Explore

Modeling data

Overview

In this section we’ll learn how to model data using the Instant Explorer. By the end of this document you’ll know how to:

  • Create namespaces and attributes
  • Add indexes, unqiue constraints, and relationship-types
  • Lock down your schema for production

We’ll build a micro-blog to illustrate. Our aim is to create the following data model:

users {
  id: UUID,
  email: string :is_unique,
  hande: string :is_unique :is_indexed,
  createdAt: number,
  :has_many posts
  :has_one pin
}

posts {
  id: UUID,
  text: string,
  createdAt: number,
  :has_many comments,
  :belongs_to author :through users,
  :has_one pin
}

comments {
  id: UUID,
  text: string,
  :belongs_to post,
  :belongs_to author :through users
}

pins {
  id: UUID,
  :has_one post,
  :has_one author :through users
}

There are four core building blocks to modeling data with Instant.

1) Namespaces

Namespaces house entities like users, posts, comments, pins. They are equivalent to “tables” in relational databases or “collections” in NoSQL.

2) Attributes

Attributes are properties associated with namespaces like id, email, posts for users. Attributes come in two flavors, data and links. They are equivalent to a “column” in relational databases or a “field” in NoSQL.

3) Data Attributes

Data attributes are facts about an entity. In our data model above these would be id, email , handle and createdAt for users

4) Link Attributes

Links connect two namespaces together. When you create a link you define a “name” and a “reverse attribute name.” For example the link between users and posts

  • Has a name of “posts” connecting users to their posts
  • Has a reverse name of “author” connecting posts to their users

Links can also have one of four relationship types: many-to-many, many-to-one, one-to-many, and one-to-one

Our micro-blog example has the following relationship types:

  • Many-to-one between users and posts
  • One-to-one between users and pins
  • Many-to-one between posts and comments
  • Many-to-one between users and comments
  • One-to-one between posts and pins

Now that we’re familiar with namespaces, attributes, data, and links. we can start modeling our data.

1. Create Namespaces

This is the most straight forward. After creating a new app in the dashboard you can simply press + Create in the dashboard to add new namespaces.

Aside from creating namespace in the explorer, namespaces are also automatically created the first time they are referenced when you call transact with update

For example. transact(tx.hello[id()].update(…) will make a hello namespace if one did not exist already.

2. Create Data Attributes

Now that we have our namespaces, we can start adding attributes.

Let’s start by adding data attributes to users. You’ll notice an id attribute has already been made for you. Let’s create the following:

email with a unique constraint so no two users have the same email

handle with a unique constraint so no two users have the same handle, and also an index because our application will use handle for fetching posts when browsing user profiles.

createdAt which doesn’t need any constraints or index.

Use the explorer in the Dashboard to create these data attributes. Here's the flow for creating handle.

  • 1: Click "Edit Schema" in the users namespace.
  • 2: Click "New Attribute"
  • 3: Configure away!

Similar to namespaces, data attributes are automatically created the first time they are referenced when you call transact with update

For example, transact(tx.users[id()].update({newAttribute: "hello world!"}) will create newAttribute on users if newAttribute did not exist before.

Next up we’ll create our link attributes on user. Specifically we want to model:

users can have many posts , but posts can only have one users via the label author

users can only have one pins, and pins can only have one users via the label author

Again we can use the dashboard to set these up. Creating the posts link attribute looks like

And creating the pins link attribute looks like

When creating links, attributes will show up under both namespaces! If you inspect the posts and pins namespaces in the explorer you should see both have an author attribute that links to users

A many-to-many link attribute is automatically created the first time two namespaces are referenced when you call transact and link

For example, transact(tx.users[id].link({pets: petId}) will create an attribute pets on users and a users attribute on pets

4. Modify or Delete Attributes and Namespaces

You can always modify or delete attributes after creating them. In the previous step we created the link attribute users.pins but we can rename it to users.pin as shown below.

Similarly you can delete whole namespaces when editing their schema.

Be aware that deleting namespaces and attributes are irreversiable operations!

5. Lock down your schema in production

In the earlier sections we mentioned that new namespaces and attributes can be created on the fly when you call transact. This can be useful for development, but you may not want this in production. To prevent changes to your schema on the fly, simply add these permissions to your app.

{
  "attrs": {
    "allow": {
      "create": "false",
      "delete": "false",
      "update": "false"
    }
  },
  ... // other permissions
}

For our micro-blog example, it would look like this in the dashboard:

With these permissions set you’ll still be able to make changes in the explorer, but client-side transactions that try to modify your schema will fail. This means your schema is safe from unwanted changes!

If you've made it this far, congratulations! You should now be able to fully customize and lock down your data model. Huzzah!