mirror of
				https://github.com/strapi/strapi.git
				synced 2025-10-31 18:08:11 +00:00 
			
		
		
		
	
		
			
	
	
		
			714 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			714 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|   | # Models
 | ||
|  | 
 | ||
|  | Strapi comes installed with a powerful Object-Relational-Mapper (ORM) called Waterline, | ||
|  | a datastore-agnostic tool that dramatically simplifies interaction with one or more databases. | ||
|  | 
 | ||
|  | Models represent a structure of data which requires persistent storage. The data may live in any data-store | ||
|  | but is interfaced in the same way. This allows your users to live in PostgreSQL and your user preferences | ||
|  | to live in MongoDB and you will interact with the data models in the exact same way. | ||
|  | 
 | ||
|  | If you're using MySQL, a model might correspond to a table. If you're using MongoDB, it might correspond | ||
|  | to a collection. In either case, the goal is to provide a simple, modular way of managing data without | ||
|  | relying on any one type of database. | ||
|  | 
 | ||
|  | Models are defined in the `./api/<apiName>/models` directory. | ||
|  | 
 | ||
|  | ## Model settings
 | ||
|  | 
 | ||
|  | The following properties can be specified at the top level of your model definition to override | ||
|  | the defaults for that particular model. | ||
|  | 
 | ||
|  | For example, this a basic model `Pet`: | ||
|  | ```js | ||
|  | { | ||
|  |   "identity": "pet", | ||
|  |   "connection": "mongoDBServer", | ||
|  |   "schema": true, | ||
|  |   "attributes": { | ||
|  |     "name": { | ||
|  |       "type": "string", | ||
|  |       "required": true | ||
|  |     }, | ||
|  |     "gender": { | ||
|  |       "type": "string", | ||
|  |       "enum": ["male", "female"] | ||
|  |     }, | ||
|  |     "age": { | ||
|  |       "type": "int", | ||
|  |       "max": 100 | ||
|  |     }, | ||
|  |     "birthDate": { | ||
|  |       "type": "date" | ||
|  |     }, | ||
|  |     "breed": { | ||
|  |       "type": "string" | ||
|  |     } | ||
|  |   }, | ||
|  |   "autoPK": true, | ||
|  |   "autoCreatedAt": true, | ||
|  |   "autoUpdatedAt": true | ||
|  | } | ||
|  | 
 | ||
|  | ``` | ||
|  | 
 | ||
|  | ### schema
 | ||
|  | 
 | ||
|  | A flag to toggle schemaless or schema mode in databases that support schemaless data structures. | ||
|  | If turned off, this will allow you to store arbitrary data in a record. If turned on, only attributes | ||
|  | defined in the model's attributes object will be stored. | ||
|  | 
 | ||
|  | For adapters that don't require a schema, such as MongoDB or Redis, the `schema` key is set to `false`. | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "schema": true|false | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### connection
 | ||
|  | 
 | ||
|  | The configured database connection where this model will fetch and save its data. | ||
|  | Defaults to `defaultSQLite`, the default connection that uses the `waterline-sqlite3` adapter. | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "connection": "mongoDBServer" | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### identity
 | ||
|  | 
 | ||
|  | The lowercase unique key for the model. By default, a model's identity is inferred automatically | ||
|  | by lowercasing its filename. You should never change this property on your models. | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "identity": "petModel" | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### globalId
 | ||
|  | 
 | ||
|  | This flag changes the global name by which you can access your model (if the globalization of models | ||
|  | is enabled). You should never change this property on your models. | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "globaId": "pets" | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | For example to access to your model function: | ||
|  | ```js | ||
|  | Pets.find().exec(function (error, pets) { | ||
|  |   if (error) { | ||
|  |     console.log(error); | ||
|  |     return false; | ||
|  |   } | ||
|  | 
 | ||
|  |   console.log(pets); | ||
|  | }); | ||
|  | ``` | ||
|  | 
 | ||
|  | ### autoPK
 | ||
|  | 
 | ||
|  | A flag to toggle the automatic definition of a primary key in your model. | ||
|  | The details of this default primary key vary between adapters. In any case, the primary keys generated | ||
|  | by `autoPK` will be unique. If turned off no primary key will be created by default, and you will need | ||
|  | to define one manually using `primaryKey: true` for one of the model attributes. | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "autoPK": true|false | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### autoCreatedAt
 | ||
|  | 
 | ||
|  | A flag to toggle the automatic definition of a `createdAt` attribute in your model. | ||
|  | By default, `createdAt` is an attribute which will be automatically set when a record is created with | ||
|  | the current timestamp. | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "autoCreatedAt": true|false | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### autoUpdatedAt
 | ||
|  | 
 | ||
|  | A flag to toggle the automatic definition of a `updatedAt` attribute in your model. | ||
|  | By default, `updatedAt` is an attribute which will be automatically set with the current timestamp | ||
|  | every time a record is updated. | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "autoUpdatedAt": true|false | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### tableName
 | ||
|  | 
 | ||
|  | You can define a custom name for the physical collection in your adapter by adding a `tableName` | ||
|  | attribute. This isn't just for tables. In MySQL, PostgreSQL, Oracle, etc. this setting refers | ||
|  | to the name of the table, but in MongoDB or Redis, it refers to the collection, and so forth. | ||
|  | If no `tableName` is specified, Waterline will use the model's `identity` as its `tableName`. | ||
|  | 
 | ||
|  | This is particularly useful for working with pre-existing/legacy databases. | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "tableName": "pets_table" | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### attributes
 | ||
|  | 
 | ||
|  | Model attributes are basic pieces of information about a model. | ||
|  | A model called `Pet` might have attributes called `name`, `gender`, `age`, | ||
|  | `birthday` and `breed`. | ||
|  | 
 | ||
|  | Options can be used to enforce various constraints and add special enhancements to model attributes. | ||
|  | 
 | ||
|  | #### type
 | ||
|  | 
 | ||
|  | Specifies the type of data that will be stored in this attribute. One of: | ||
|  | - `string` | ||
|  | - `text` | ||
|  | - `integer` | ||
|  | - `float` | ||
|  | - `date` | ||
|  | - `datetime` | ||
|  | - `boolean` | ||
|  | - `binary` | ||
|  | - `array` | ||
|  | - `json` | ||
|  | 
 | ||
|  | Defaults to `string` if not specified. | ||
|  | 
 | ||
|  | ### Validations
 | ||
|  | 
 | ||
|  | Strapi bundles support for automatic validations of your models' attributes. | ||
|  | Any time a record is updated, or a new record is created, the data for each attribute will | ||
|  | be checked against all of your predefined validation rules. This provides a convenient failsafe | ||
|  | to ensure that invalid entries don't make their way into your application's database(s). | ||
|  | 
 | ||
|  | Validations are defined directly in your collection attributes. | ||
|  | 
 | ||
|  | - `after` (date): Checks if string date in this record is after the specified `Date`. | ||
|  |   Must be valid JavaScript `Date`. | ||
|  | - `alpha` (boolean): Checks if string in this record contains only letters (a-zA-Z). | ||
|  | - `alphadashed` (boolean): Checks if string in this record contains only numbers and/or dashes. | ||
|  | - `alphanumeric` (boolean): Checks if string in this record contains only letters and numbers. | ||
|  | - `alphanumericdashed` (boolean): Checks if string in this record contains only numbers and/or | ||
|  |   letters and/or dashes. | ||
|  | - `array` (boolean): Checks if this record is a valid JavaScript array object. | ||
|  |   Strings formatted as arrays will fail. | ||
|  | - `before` (date): Checks if string in this record is a date that's before the specified date. | ||
|  | - `binary` (boolean): Checks if this record is a valid binary data. Strings will pass. | ||
|  | - `boolean` (boolean): Checks if this record is a valid boolean. Strings will fail. | ||
|  | - `contains` (string): Checks if string in this record contains the seed. | ||
|  | - `creditcard` (boolean): Checks if string in this record is a credit card. | ||
|  | - `date` (boolean): Checks if string in this record is a date takes both strings and JavaScript. | ||
|  | - `datetime` (boolean): Checks if string in this record looks like a JavaScript `datetime`. | ||
|  | - `decimal` (boolean): Checks if it contains a decimal or is less than 1. | ||
|  | - `email` (boolean): Checks if string in this record looks like an email address. | ||
|  | - `empty` (boolean): Checks if the entry is empty. Arrays, strings, or arguments objects with | ||
|  |   a length of 0 and objects with no | ||
|  |   own enumerable properties are considered empty. | ||
|  | - `equals` (integer): Checks if string in this record is equal to the specified value. | ||
|  |   They must match in both value and type. | ||
|  | - `falsey` (boolean): Would a Javascript engine register a value of `false` on this?. | ||
|  | - `finite` (boolean): Checks if given value is, or can be coerced to, a finite number. | ||
|  |   This is not the same as native `isFinite` | ||
|  |   which will return `true` for booleans and empty strings. | ||
|  | - `float` (boolean): Checks if string in this record is of the number type float. | ||
|  | - `hexadecimal` (boolean): Checks if string in this record is a hexadecimal number. | ||
|  | - `hexColor` (boolean): Checks if string in this record is a hexadecimal color. | ||
|  | - `in` (array): Checks if string in this record is in the specified array of allowed | ||
|  |   string values. | ||
|  | - `int` (boolean): Check if string in this record is an integer. | ||
|  | - `integer` (boolean): Check if string in this record is an integer. Alias for `int`. | ||
|  | - `ip` (boolean): Checks if string in this record is a valid IP (v4 or v6). | ||
|  | - `ipv4` (boolean): Checks if string in this record is a valid IP v4. | ||
|  | - `ipv6` (boolean): Checks if string in this record is aa valid IP v6. | ||
|  | - `json` (boolean): Checks if the record is a JSON. | ||
|  | - `lowercase` (boolean): Check if string in this record is in all lowercase. | ||
|  | - `max` (integer): max value for an integer. | ||
|  | - `maxLength` (integer): | ||
|  | - `min` (integer): min value for an integer. | ||
|  | - `minLength` (integer): | ||
|  | - `notContains` (string): Checks if string in this record doesn't contain the seed. | ||
|  | - `notIn` (array): does the value of this model attribute exist inside of the defined | ||
|  |   validator value (of the same type). | ||
|  |   Takes strings and arrays. | ||
|  | - `notNull` (boolean): does this not have a value of `null` ?. | ||
|  | - `null` (boolean): Checks if string in this record is null. | ||
|  | - `number` (boolean): Checks if this record is a number. `NaN` is considered a number. | ||
|  | - `numeric` (boolean): Checks if string in this record contains only numbers. | ||
|  | - `object` (boolean): Checks if this attribute is the language type of Object. | ||
|  |   Passes for arrays, functions, objects, | ||
|  |   regexes, new Number(0), and new String('') ! | ||
|  | - `regex` (regex): Checks if the record matches the specific regex. | ||
|  | - `required` (boolean): Must this model attribute contain valid data before a new | ||
|  |   record can be created?. | ||
|  | - `string` (boolean): Checks if the record is a string. | ||
|  | - `text` (boolean): Checks if the record is a text. | ||
|  | - `truthy` (boolean): Would a Javascript engine register a value of `false` on this? | ||
|  | - `undefined` (boolean): Would a JavaScript engine register this thing as have the | ||
|  |   value `undefined`? | ||
|  | - `uppercase` (boolean): Checks if string in this record is uppercase. | ||
|  | - `url` (boolean): Checks if string in this record is a URL. | ||
|  | - `urlish` (boolean): Checks if string in this record contains something that looks like | ||
|  |   a route, ending with a file extension. | ||
|  | - `uuid` (boolean): Checks if string in this record is a UUID (v3, v4, or v5). | ||
|  | - `uuidv3` (boolean): Checks if string in this record is a UUID (v3). | ||
|  | - `uuidv4` (boolean): Checks if string in this record is a UUID (v4). | ||
|  | 
 | ||
|  | #### defaultsTo
 | ||
|  | 
 | ||
|  | When a record is created, if no value was supplied, the record will be created with the specified | ||
|  | `defaultsTo` value. | ||
|  | 
 | ||
|  | ```js | ||
|  | "attributes": { | ||
|  |   "usersGroup": { | ||
|  |     "type": "string", | ||
|  |     "defaultsTo": "guess" | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | #### autoIncrement
 | ||
|  | 
 | ||
|  | Sets up the attribute as an auto-increment key. When a new record is added to the model, | ||
|  | if a value for this attribute is not specified, it will be generated by incrementing the most recent | ||
|  | record's value by one. | ||
|  | 
 | ||
|  | Attributes which specify `autoIncrement` should always be of `type: integer`. | ||
|  | Also, bear in mind that the level of support varies across different datastores. | ||
|  | For instance, MySQL will not allow more than one auto-incrementing column per table. | ||
|  | 
 | ||
|  | ```js | ||
|  | "attributes": { | ||
|  |   "placeInLine": { | ||
|  |     "type": "integer", | ||
|  |     "autoIncrement": true | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | #### unique
 | ||
|  | 
 | ||
|  | Ensures no two records will be allowed with the same value for the target attribute. | ||
|  | This is an adapter-level constraint, so in most cases this will result in a unique index on the | ||
|  | attribute being created in the underlying datastore. | ||
|  | 
 | ||
|  | Defaults to `false` if not specified. | ||
|  | 
 | ||
|  | ```js | ||
|  | "attributes": { | ||
|  |   "username": { | ||
|  |     "type": "string", | ||
|  |     "unique": true | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | #### primaryKey
 | ||
|  | 
 | ||
|  | Use this attribute as the the primary key for the record. Only one attribute per model can be the | ||
|  | `primaryKey`. Defaults to `false` if not specified. | ||
|  | 
 | ||
|  | This should never be used unless `autoPK` is set to `false`. | ||
|  | 
 | ||
|  | ```js | ||
|  | "attributes": { | ||
|  |   "uuid": { | ||
|  |     "type": "string", | ||
|  |     "primaryKey": true, | ||
|  |     "required": true | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | #### enum
 | ||
|  | 
 | ||
|  | A special validation property which only saves data which matches a whitelisted set of values. | ||
|  | 
 | ||
|  | ```js | ||
|  | "attributes": { | ||
|  |   "gender": { | ||
|  |     "type": "string", | ||
|  |     "enum": ["male", "female"] | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | #### size
 | ||
|  | 
 | ||
|  | If supported in the adapter, can be used to define the size of the attribute. | ||
|  | For example in MySQL, `size` can be specified as a number (`n`) to create a column with the SQL | ||
|  | data type: `varchar(n)`. | ||
|  | 
 | ||
|  | ```js | ||
|  | "attributes": { | ||
|  |   "name": { | ||
|  |     "type": "string", | ||
|  |     "size": 24 | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | #### columnName
 | ||
|  | 
 | ||
|  | Inside an attribute definition, you can specify a `columnName` to force Waterline to store data | ||
|  | for that attribute in a specific column in the configured connection. | ||
|  | Be aware that this is not necessarily SQL-specific. It will also work for MongoDB fields, etc. | ||
|  | 
 | ||
|  | While the `columnName` property is primarily designed for working with existing/legacy databases, | ||
|  | it can also be useful in situations where your database is being shared by other applications, | ||
|  | or you don't have access permissions to change the schema. | ||
|  | 
 | ||
|  | ```js | ||
|  | "attributes": { | ||
|  |   "name": { | ||
|  |     "type": "string", | ||
|  |     "columnName": "pet_name" | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ## Associations
 | ||
|  | 
 | ||
|  | With Waterline you can associate models with other models across all data stores. | ||
|  | This means that your users can live in PostgreSQL and their photos can live in MongoDB | ||
|  | and you can interact with the data as if they lived together on the same database. | ||
|  | You can also have associations that live on separate connections or in different databases | ||
|  | within the same adapter. | ||
|  | 
 | ||
|  | ### One-Way associations
 | ||
|  | 
 | ||
|  | A one-way association is where a model is associated with another model. | ||
|  | You could query that model and populate to get the associated model. | ||
|  | You can't however query the associated model and populate to get the associating model. | ||
|  | 
 | ||
|  | In this example, we are associating a `User` with a `Pet` but not a `Pet` with a `User`. | ||
|  | Because we have only formed an association on one of the models, a `Pet` has no restrictions | ||
|  | on the number of `User` models it can belong to. If we wanted to, we could change this and | ||
|  | associate the `Pet` with exactly one `User` and the `User` with exactly one `Pet`. | ||
|  | 
 | ||
|  | `./api/pet/models/Pet.settings.json`: | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "attributes": { | ||
|  |     "name": { | ||
|  |       "type": "string", | ||
|  |       "required": true, | ||
|  |       "unique": true | ||
|  |     }, | ||
|  |     "color": { | ||
|  |       "type": "string", | ||
|  |       "required": true | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | `./api/user/models/User.settings.json`: | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "attributes": { | ||
|  |     "name": { | ||
|  |       "type": "string", | ||
|  |       "required": true, | ||
|  |       "unique": true | ||
|  |     }, | ||
|  |     "color": { | ||
|  |       "type": "string", | ||
|  |       "required": true | ||
|  |     }, | ||
|  |     "pony": { | ||
|  |       "model": "pet" | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### One-to-One associations
 | ||
|  | 
 | ||
|  | A one-to-one association states that a model may only be associated with one other model. | ||
|  | In order for the model to know which other model it is associated with a foreign key must | ||
|  | be included in the record. | ||
|  | 
 | ||
|  | In this example, we are associating a `Pet` with a `User`. The `User` may only have one | ||
|  | `Pet` and viceversa, a `Pet` can only have one `User`. However, in order to query this association | ||
|  | from both sides, you will have to create/update both models. | ||
|  | 
 | ||
|  | `./api/pet/models/Pet.settings.json`: | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "attributes": { | ||
|  |     "name": { | ||
|  |       "type": "string", | ||
|  |       "required": true, | ||
|  |       "unique": true | ||
|  |     }, | ||
|  |     "color": { | ||
|  |       "type": "string", | ||
|  |       "required": true | ||
|  |     }, | ||
|  |     "owner": { | ||
|  |       "model": "user" | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | `./api/user/models/User.settings.json`: | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "attributes": { | ||
|  |     "name": { | ||
|  |       "type": "string", | ||
|  |       "required": true, | ||
|  |       "unique": true | ||
|  |     }, | ||
|  |     "age": { | ||
|  |       "type": "integer", | ||
|  |       "required": true | ||
|  |     }, | ||
|  |     "pony": { | ||
|  |       "model": "pet" | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### One-to-Many associations
 | ||
|  | 
 | ||
|  | A one-to-many association states that a model can be associated with many other models. | ||
|  | To build this association a virtual attribute is added to a model using the `collection` property. | ||
|  | In a one-to-many association one side must have a `collection` attribute and the other side must contain a | ||
|  | `model` attribute. This allows the many side to know which records it needs to get when a `populate` is used. | ||
|  | 
 | ||
|  | Because you may want a model to have multiple one-to-many associations on another model a `via` key is | ||
|  | needed on the `collection` attribute. This states which `model` attribute on the one side of the association | ||
|  | is used to populate the records. | ||
|  | 
 | ||
|  | In this example, a `User` can have several `Pet`, but a `Pet` has only one `owner` (from the `User` model). | ||
|  | 
 | ||
|  | `./api/pet/models/Pet.settings.json`: | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "attributes": { | ||
|  |     "name": { | ||
|  |       "type": "string", | ||
|  |       "required": true, | ||
|  |       "unique": true | ||
|  |     }, | ||
|  |     "color": { | ||
|  |       "type": "string", | ||
|  |       "required": true | ||
|  |     }, | ||
|  |     "owner": { | ||
|  |       "model": "user" | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | `./api/user/models/User.settings.json`: | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "attributes": { | ||
|  |     "name": { | ||
|  |       "type": "string", | ||
|  |       "required": true, | ||
|  |       "unique": true | ||
|  |     }, | ||
|  |     "age": { | ||
|  |       "type": "integer", | ||
|  |       "required": true | ||
|  |     }, | ||
|  |     "pets": { | ||
|  |       "collection": "pet", | ||
|  |       "via": "owner" | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ### Many-to-Many associations
 | ||
|  | 
 | ||
|  | A many-to-many association states that a model can be associated with many other models | ||
|  | and vice-versa. Because both models can have many related models a new join table will | ||
|  | need to be created to keep track of these relations. | ||
|  | 
 | ||
|  | Waterline will look at your models and if it finds that two models both have `collection` | ||
|  | attributes that point to each other, it will automatically build up a join table for you. | ||
|  | 
 | ||
|  | Because you may want a model to have multiple many-to-many associations on another model | ||
|  | a `via` key is needed on the `collection` attribute. This states which `model` attribute on the | ||
|  | one side of the association is used to populate the records. | ||
|  | 
 | ||
|  | Using the `User` and `Pet` example lets look at how to build a schema where a `User` may | ||
|  | have many `Pet` records and a `Pet` may have multiple owners. | ||
|  | 
 | ||
|  | In this example, we will start with an array of users and an array of pets. | ||
|  | We will create records for each element in each array then associate all of the `Pets` with all | ||
|  | of the `Users`. If everything worked properly, we should be able to query any `User` and see that | ||
|  | they _own_ all of the `Pets`. Furthermore, we should be able to query any `Pet` and see that | ||
|  | it is _owned_ by every `User`. | ||
|  | 
 | ||
|  | `./api/pet/models/Pet.settings.json`: | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "attributes": { | ||
|  |     "name": { | ||
|  |       "type": "string", | ||
|  |       "required": true, | ||
|  |       "unique": true | ||
|  |     }, | ||
|  |     "color": { | ||
|  |       "type": "string", | ||
|  |       "required": true | ||
|  |     }, | ||
|  |     "owners": { | ||
|  |       "collection": "user", | ||
|  |       "via": "pets" | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | `./api/user/models/User.settings.json`: | ||
|  | 
 | ||
|  | ```js | ||
|  | { | ||
|  |   "attributes": { | ||
|  |     "name": { | ||
|  |       "type": "string", | ||
|  |       "required": true, | ||
|  |       "unique": true | ||
|  |     }, | ||
|  |     "age": { | ||
|  |       "type": "integer", | ||
|  |       "required": true | ||
|  |     }, | ||
|  |     "pets": { | ||
|  |       "collection": "pet", | ||
|  |       "via": "owners" | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | ## Lifecycle Callbacks
 | ||
|  | 
 | ||
|  | Lifecycle callbacks are functions you can define to run at certain times in a query. | ||
|  | They are hooks that you can tap into in order to change data. | ||
|  | 
 | ||
|  | Strapi exposes a handful of lifecycle callbacks by default. | ||
|  | 
 | ||
|  | ### Callbacks on create
 | ||
|  | 
 | ||
|  | - `beforeValidate`: `fn(values, cb)` | ||
|  | - `afterValidate`: `fn(values, cb)` | ||
|  | - `beforeCreate`: `fn(values, cb)` | ||
|  | - `afterCreate`: `fn(newlyInsertedRecord, cb)` | ||
|  | 
 | ||
|  | ### Callbacks on update
 | ||
|  | 
 | ||
|  | - `beforeValidate: fn(valuesToUpdate, cb)` | ||
|  | - `afterValidate: fn(valuesToUpdate, cb)` | ||
|  | - `beforeUpdate: fn(valuesToUpdate, cb)` | ||
|  | - `afterUpdate: fn(updatedRecord, cb)` | ||
|  | 
 | ||
|  | ### Callbacks on destroy
 | ||
|  | 
 | ||
|  | - `beforeDestroy`: `fn(criteria, cb)` | ||
|  | - `afterDestroy`: `fn(deletedRecord, cb)` | ||
|  | 
 | ||
|  | 
 | ||
|  | For example, this could be your `./api/pet/models/Pet.js` file: | ||
|  | ```js | ||
|  | module.exports = { | ||
|  |   /** | ||
|  |    * Basic settings | ||
|  |    */ | ||
|  | 
 | ||
|  |   // The identity to use. | ||
|  |   identity: settings.identity, | ||
|  | 
 | ||
|  |   // The connection to use. | ||
|  |   connection: settings.connection, | ||
|  | 
 | ||
|  |   // Do you want to respect schema? | ||
|  |   schema: settings.schema, | ||
|  | 
 | ||
|  |   // Merge simple attributes from settings with those ones. | ||
|  |   attributes: _.merge(settings.attributes, { | ||
|  | 
 | ||
|  |   }), | ||
|  | 
 | ||
|  |   // Do you automatically want to have time data? | ||
|  |   autoCreatedAt: settings.autoCreatedAt, | ||
|  |   autoUpdatedAt: settings.autoUpdatedAt, | ||
|  | 
 | ||
|  |   /** | ||
|  |    * Lifecycle callbacks on create | ||
|  |    */ | ||
|  | 
 | ||
|  |   // Before creating a value. | ||
|  |   beforeCreate: function (values, next) { | ||
|  |     // Do some stuff | ||
|  |     next(); | ||
|  |   }, | ||
|  | 
 | ||
|  |   // After creating a value. | ||
|  |   afterCreate: function (newlyInsertedRecord, next) { | ||
|  |     // Do some stuff | ||
|  |     next(); | ||
|  |   }, | ||
|  | 
 | ||
|  |   /** | ||
|  |    * Lifecycle callbacks on update | ||
|  |    */ | ||
|  | 
 | ||
|  |   // Before updating a value. | ||
|  |   beforeUpdate: function (valuesToUpdate, next) { | ||
|  |     // Do some stuff | ||
|  |     next(); | ||
|  |   }, | ||
|  | 
 | ||
|  |   // After updating a value. | ||
|  |   afterUpdate: function (updatedRecord, next) { | ||
|  |     // Do some stuff | ||
|  |     next(); | ||
|  |   }, | ||
|  | 
 | ||
|  |   /** | ||
|  |    * Lifecycle callbacks on destroy | ||
|  |    */ | ||
|  | 
 | ||
|  |   // Before destroying a value. | ||
|  |   beforeDestroy: function (criteria, next) { | ||
|  |     // Do some stuff | ||
|  |     next(); | ||
|  |   }, | ||
|  | 
 | ||
|  |   // After destroying a value. | ||
|  |   afterDestroy: function (destroyedRecords, next) { | ||
|  |     // Do some stuff | ||
|  |     next(); | ||
|  |   } | ||
|  | ``` |