2017-10-10 11:15:24 +02:00
# Models
2017-10-11 12:47:01 +02:00
See the [models' concepts ](../concepts/concepts.md#models ) for details.
2017-10-10 11:15:24 +02:00
## How to create a model?
Use the CLI, and run the following command `strapi generate:model user firstname:string lastname:string` . Read the [CLI documentation ](../cli/CLI.md ) for more informations.
This will create two files located at `./api/user/models` :
2017-10-12 12:19:30 +02:00
- `User.settings.json` : contains the list of attributes and settings. The JSON format makes the file easily editable.
2017-10-10 11:15:24 +02:00
- `User.js` : imports `User.settings.json` and extends it with additional settings and lifecycle callbacks.
> Note: when you create a new API using the CLI (`strapi generate:api <name>`), a model is automatically created.
## Define the attributes
The following types are currently available:
- `string`
- `text`
- `integer`
- `biginteger`
- `float`
- `decimal`
2017-11-28 13:53:08 +01:00
- `password`
2017-10-10 11:15:24 +02:00
- `date`
- `time`
- `datetime`
- `timestamp`
- `boolean`
- `binary`
- `uuid`
- `enumeration`
- `json`
2017-11-28 16:01:50 +01:00
- `email`
2017-10-10 11:15:24 +02:00
#### Example
**Path —** `User.settings.json` .
```json
{
"connection": "default",
"info": {
"name": "user",
"description": "This represents the User Model"
},
"attributes": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
},
2017-11-28 13:53:08 +01:00
"password": {
"type": "password"
},
2017-10-10 11:15:24 +02:00
"about": {
"type": "description"
},
"age": {
"type": "integer"
},
"birthday": {
"type": "date"
}
}
}
```
## Relations
2017-10-11 12:47:01 +02:00
Refer to the [relations concept ](../concepts/concepts.md#relations ) for more informations about relations type.
2017-10-10 11:15:24 +02:00
### Many-to-many
2017-10-11 12:47:01 +02:00
Refer to the [many-to-many concept ](../concepts/concepts.md#many-to-many ).
2017-10-10 11:15:24 +02:00
#### Example
A `product` can be related to many `categories` , so a `category` can have many `products` .
**Path —** `./api/product/models/Product.settings.json` .
2017-10-12 12:19:30 +02:00
```json
2017-10-10 11:15:24 +02:00
{
"attributes": {
"categories": {
"collection": "product",
"via": "products",
"dominant": true
}
}
}
```
> Note: The `dominant` key allows you to define in which table/collection (only for NoSQL databases) should be stored the array that defines the relationship. Because there is no join table in NoSQL, this key is required for NoSQL databases (ex: MongoDB).
**Path —** `./api/category/models/Category.settings.json` .
2017-10-12 12:19:30 +02:00
```json
2017-10-10 11:15:24 +02:00
{
"attributes": {
"products": {
"collection": "category",
"via": "categories"
}
}
}
```
**Path —** `./api/product/controllers/Product.js` .
```js
2017-10-12 12:19:30 +02:00
// Mongoose example
2017-10-10 11:15:24 +02:00
module.exports = {
2017-10-12 12:19:30 +02:00
findProductsWithCategories: async (ctx) => {
2017-10-10 11:15:24 +02:00
// Retrieve the list of products.
const products = Product
.find()
.populate('categories');
// Send the list of products.
ctx.body = products;
}
}
```
**Path —** `./api/category/controllers/Category.js` .
```js
2017-10-12 12:19:30 +02:00
// Mongoose example
2017-10-10 11:15:24 +02:00
module.exports = {
2017-10-12 12:19:30 +02:00
findCategoriesWithProducts: async (ctx) => {
2017-10-10 11:15:24 +02:00
// Retrieve the list of categories.
const categories = Category
.find()
.populate('products');
// Send the list of categories.
ctx.body = categories;
}
}
```
### One-to-many
2017-10-11 12:47:01 +02:00
Refer to the [one-to-many concept ](../concepts/concepts.md#one-to-many ) for more informations.
2017-10-10 11:15:24 +02:00
#### Example
A `user` can have many `articles` , and an `article` can be related to one `user` (author).
2017-10-11 10:51:28 +02:00
**Path —** `./api/user/models/User.settings.json` .
2017-10-12 12:19:30 +02:00
```json
2017-10-10 11:15:24 +02:00
{
"attributes": {
"articles": {
"collection": "article",
"via": "author"
}
}
}
```
**Path —** `./api/article/models/Article.settings.json` .
2017-10-12 12:19:30 +02:00
```json
2017-10-10 11:15:24 +02:00
{
"attributes": {
"author": {
"model": "user"
}
}
}
```
**Path —** `./api/user/controllers/User.js` .
```js
2017-10-12 12:19:30 +02:00
// Mongoose example
2017-10-10 11:15:24 +02:00
module.exports = {
2017-10-12 12:19:30 +02:00
findUsersWithArticles: async (ctx) => {
2017-10-10 11:15:24 +02:00
// Retrieve the list of users with their articles.
const users = User
.find()
.populate('articles');
// Send the list of users.
ctx.body = users;
}
}
```
**Path —** `./api/article/controllers/Article.js` .
```js
2017-10-12 12:19:30 +02:00
// Mongoose example
2017-10-10 11:15:24 +02:00
module.exports = {
2017-10-12 12:19:30 +02:00
findArticlesWithAuthors: async (ctx) => {
2017-10-10 11:15:24 +02:00
// Retrieve the list of articles with their authors.
const articles = Article
.find()
.populate('author');
// Send the list of users.
ctx.body = users;
}
}
```
### One-to-one
2017-10-11 12:47:01 +02:00
Refer to the [one-to-one concept ](../concepts/concepts.md#one-to-one ) for informations.
2017-10-10 11:15:24 +02:00
#### Example
A `user` can have one `address` . And this address is only related to this `user` .
**Path —** `./api/user/models/User.settings.json` .
2017-10-12 12:19:30 +02:00
```json
2017-10-10 11:15:24 +02:00
{
"attributes": {
"address": {
2017-10-12 12:19:30 +02:00
"model": "address",
"via": "user"
2017-10-10 11:15:24 +02:00
}
}
}
```
**Path —** `./api/address/models/Address.settings.json` .
2017-10-12 12:19:30 +02:00
```json
2017-10-10 11:15:24 +02:00
{
"attributes": {
"user": {
"model": "user"
}
}
}
```
**Path —** `./api/user/controllers/User.js` .
```js
2017-10-12 12:19:30 +02:00
// Mongoose example
2017-10-10 11:15:24 +02:00
module.exports = {
2017-10-12 12:19:30 +02:00
findUsersWithAddresses: async (ctx) => {
2017-10-10 11:15:24 +02:00
// Retrieve the list of users with their addresses.
const users = User
.find()
.populate('address');
// Send the list of users.
ctx.body = users;
}
}
```
**Path —** `./api/adress/controllers/Address.js` .
```js
2017-10-12 12:19:30 +02:00
// Mongoose example
2017-10-10 11:15:24 +02:00
module.exports = {
2017-10-12 12:19:30 +02:00
findArticlesWithUsers: async (ctx) => {
2017-10-10 11:15:24 +02:00
// Retrieve the list of addresses with their users.
const articles = Address
.find()
.populate('user');
// Send the list of addresses.
ctx.body = addresses;
}
}
```
### One-way
2017-10-11 12:47:01 +02:00
Refer to the [one-way concept ](../concepts/concepts.md#one-way ) for informations.
2017-10-10 11:15:24 +02:00
#### Example
A `pet` can be owned by someone (a `user` ).
**Path —** `./api/pet/models/Pet.settings.json` .
2017-10-12 12:19:30 +02:00
```json
2017-10-10 11:15:24 +02:00
{
"attributes": {
"owner": {
"model": "user"
}
}
}
```
**Path —** `./api/pet/controllers/Pet.js` .
```js
2017-10-12 12:19:30 +02:00
// Mongoose example
2017-10-10 11:15:24 +02:00
module.exports = {
2017-10-12 12:19:30 +02:00
findPetsWithOwners: async (ctx) => {
2017-10-10 11:15:24 +02:00
// Retrieve the list of pets with their owners.
const pets = Pet
.find()
.populate('owner');
// Send the list of pets.
ctx.body = pets;
}
}
```
## Lifecycle callbacks
2017-10-11 12:47:01 +02:00
Refer to the [lifecycle callbacks concepts ](../concepts/concepts.md#lifecycle-callbacks ) for informations.
2017-10-10 11:15:24 +02:00
The following events are available by default:
Callbacks on `save` :
- beforeSave
- afterSave
Callbacks on `fetch` :
- beforeFetch
- afterFetch
Callbacks on `create` :
- beforeCreate
- afterCreate
Callbacks on `update` :
- beforeUpdate
- afterUpdate
Callbacks on `destroy` :
- beforeDestroy
- afterDestroy
2017-10-12 12:19:30 +02:00
#### Mongoose
2017-10-10 11:15:24 +02:00
Each of these functions receives a parameter called `next` , which is the callback you should call after your logic is executed. The entry is accessible through `this` .
2017-10-12 12:19:30 +02:00
**Path —** `./api/user/models/User.js` .
```js
module.exports = {
/**
* Triggered before user creation.
*/
beforeCreate: function (next) {
// Hash password.
strapi.api.user.services.user.hashPassword(this.password)
.then((passwordHashed) => {
// Set the password.
this.password = passwordHashed;
// Execute the callback.
next();
})
.catch((error) => {
next(error);
});
}
}
}
```
#### Bookshelf
Each of these functions receives a three parameters `model` , `attrs` and `options` . You have to return a Promise.
2017-10-10 11:15:24 +02:00
**Path —** `./api/user/models/User.js` .
```js
module.exports = {
2017-10-12 12:19:30 +02:00
2017-10-10 11:15:24 +02:00
/**
* Triggered before user creation.
*/
2017-10-12 12:19:30 +02:00
beforeCreate: function (model, attrs, options) {
return new Promise((resolve, reject) => {
// Hash password.
strapi.api.user.services.user.hashPassword(model.attributes.password)
.then((passwordHashed) => {
// Set the password.
model.set('password', passwordHashed);
// Execute the callback.
resolve();
})
.catch((error) => {
reject(error);
});
}
});
2017-10-10 11:15:24 +02:00
}
}
```
## Settings
Additional settings can be set on models:
- `connection` (string) - Connection's name which must be used. Default value: `default` .
- `collectionName` (string) - Collection's name (or table's name) in which the data should be stored.
- `globalId` (string) -Global variable name for this model (case-sensitive).
**Path —** `User.settings.json` .
```json
{
2017-10-12 12:19:30 +02:00
"connection": "mongo",
"collectionName": "Users_v1",
"globalId": "Users",
"attributes": {
2017-11-28 13:53:08 +01:00
2017-10-12 12:19:30 +02:00
}
2017-10-10 11:15:24 +02:00
}
```
In this example, the model `User` will be accessible through the `Users` global variable. The data will be stored in the `Users_v1` collection or table and the model will use the `mongo` connection defined in `./config/environments/**/database.json`
> Note: The `connection` value can be changed whenever you want, but you should be aware that there is no automatic data migration process. Also if the new connection doesn't use the same ORM you will have to rewrite your queries.