Radiks allows you to model your client data. You can then query this data and display it for user in multi-player applications. For example, a social application where users want to see the comments of other users. This page explains how to create a model in your distributed application using Radiks.
Blockstack provides a `Model` class you should extend to easily create, save, and fetch models. To create a model class, import the `Model` class from `radiks` into your application.
Then, create a class that extends this model, and provide a schema. Refer to <ahref="https://github.com/blockstack/radiks/blob/master/src/model.ts"target="_blank">the <code>Model</code> class</a> in the `radiks` repo to get an overview of the class functionality.
Your new class must define a static `className` property manually. This property is used when storing and querying information. If you don't add a `className`, Radiks defaults to the actual model's class name. In production, your code should be minified, and the actual class name will be different. For this reason, it's highly recommended that you define the `className` manually.
{% include question.html content="The sentence with the statement that the actual class name will be different doesn't parse. The actual class name will be different from the model class name? the className as defined --- what? Also, what do you mean by defining the class name manually -- you mean in the code as opposed to default to the model class name"%}
The `key` in this object is the field name and the value, for example, `String`, `Boolean`, or `Number`. In this case, the `title` is a `String` field. Alternatively, you can pass options instead of a type.
To define options, pass an object, with a mandatory `type` field. The only supported option right now is `decrypted`. This defaults to `false`, meaning the field is encrypted before the data is stored publicly. If you specify `true`, then the field is not encrypted.
Storing unencrypted fields is useful if you want to be able to query the field when fetching data. A good use-case for storing decrypted fields is to store a `foreignId` that references a different model, for a "belongs-to" type of relation.
**Never add the `decrypted` option to fields that contain sensitive user data.** Blockstack data is stored in a decentralized Gaia storage and anyone can read the user's data. That's why encrypting it is so important. If you want to filter sensitive data, then you should do it on the client-side, after decrypting it.
You may want to include an optional `defaults` static property for some field values. For example in the class below the `likesDogs` field is a `Boolean` and the default is `true`.
Radiks also supplies <ahref="https://github.com/blockstack/radiks/blob/master/src/models/user.ts"target="_blank">a default <code>User</code> model</a>. You can also extend this model to add your own attributes.
// For example I want to add a public name on my user model
class MyAppUserModel extends User {
static schema = {
...User.schema,
displayName: {
type: String,
decrypted: true,
},
};
}
```
The default `User` model defines a `username` but you can add a `displayName` to allow the user to define a name unique in your app.
## Use a model you have defined
In this section, you learn how to use a model you have defined.
### About the _id attribute
All model instances have an `_id` attribute. An `_id` is used as a primary key when storing data, and is used for fetching a model. Radiks also creates a `createdAt` and `updatedAt` property when creating and saving models.
If, when constructing a model, you don't pass an `_id`, Radiks creates an `_id` for you automatically. This automatically created id uses the [`uuid/v4`](https://github.com/kelektiv/node-uuid) format.
{% include question.html content="I don't see an example of the _id attribute in the above construction. How does the user get the id to pass to findByID below then?"%}
{% include question.html content="You mention calling fetch but your example uses findById. it looks like either will work but do you want to use fetch in this example?"%}
To save a model to Gaia and MongoDB, call the `save()` method which returns a promise. This method encrypts all attributes that do not have the `decrypted` option in their schema. Then, it saves a JSON representation of the model in Gaia, as well as in the MongoDB.
To fetch multiple records that match a certain query, use the class's `fetchList()` function. This method creates an HTTP query to Radiks-server, which then queries the underlying database. Radiks-server uses the `query-to-mongo` package to turn an HTTP query into a MongoDB query.
You can read the [`query-to-mongo`](https://github.com/pbatey/query-to-mongo) package documentation to learn how to do complex querying, sorting, limiting, and so forth.
Use the `fetchOwnList` method to find models that were created by the current user. By using this method, you can preserve privacy, because Radiks uses a `signingKey` that only the current user knows.
It is common for applications to have multiple different models, where some reference another. For example, imagine a task-tracking application where a user has multiple projects, and each project has multiple tasks. Here's what those models might look like: