Model Basics

In this tutorial you will learn what models are in Sequelize and how to use them.

Concept

Models are the essence of Sequelize. A model is an abstraction that represents a table in your database. In Sequelize, it is a class that extends Model.

The model tells Sequelize several things about the entity it represents, such as the name of the table in the database and which columns it has (and their data types).

A model in Sequelize has a name. This name does not have to be the same name of the table it represents in the database. Usually, models have singular names (such as User) while tables have pluralized names (such as Users), although this is fully configurable.

Model Definition

Models can be defined in two equivalent ways in Sequelize:

After a model is defined, it is available within sequelize.models by its model name.

To learn with an example, we will consider that we want to create a model to represent users, which have a firstName and a lastName. We want our model to be called User, and the table it represents is called Users in the database.

Both ways to define this model are shown below. After being defined, we can access our model with sequelize.models.User.

Using sequelize.define:

  1. const { Sequelize, DataTypes } = require('sequelize');
  2. const sequelize = new Sequelize('sqlite::memory:');
  3. const User = sequelize.define('User', {
  4. // Model attributes are defined here
  5. firstName: {
  6. type: DataTypes.STRING,
  7. allowNull: false
  8. },
  9. lastName: {
  10. type: DataTypes.STRING
  11. // allowNull defaults to true
  12. }
  13. }, {
  14. // Other model options go here
  15. });
  16. // `sequelize.define` also returns the model
  17. console.log(User === sequelize.models.User); // true

Extending Model

  1. const { Sequelize, DataTypes, Model } = require('sequelize');
  2. const sequelize = new Sequelize('sqlite::memory');
  3. class User extends Model {}
  4. User.init({
  5. // Model attributes are defined here
  6. firstName: {
  7. type: DataTypes.STRING,
  8. allowNull: false
  9. },
  10. lastName: {
  11. type: DataTypes.STRING
  12. // allowNull defaults to true
  13. }
  14. }, {
  15. // Other model options go here
  16. sequelize, // We need to pass the connection instance
  17. modelName: 'User' // We need to choose the model name
  18. });
  19. // the defined model is the class itself
  20. console.log(User === sequelize.models.User); // true

Internally, sequelize.define calls Model.init, so both approaches are essentially equivalent.

Table name inference

Observe that, in both methods above, the table name (Users) was never explicitly defined. However, the model name was given (User).

By default, when the table name is not given, Sequelize automatically pluralizes the model name and uses that as the table name. This pluralization is done under the hood by a library called inflection, so that irregular plurals (such as person -> people) are computed correctly.

Of course, this behavior is easily configurable.

Enforcing the table name to be equal to the model name

You can stop the auto-pluralization performed by Sequelize using the freezeTableName: true option. This way, Sequelize will infer the table name to be equal to the model name, without any modifications:

  1. sequelize.define('User', {
  2. // ... (attributes)
  3. }, {
  4. freezeTableName: true
  5. });

The example above will create a model named User pointing to a table also named User.

This behavior can also be defined globally for the sequelize instance, when it is created:

  1. const sequelize = new Sequelize('sqlite::memory:', {
  2. define: {
  3. freezeTableName: true
  4. }
  5. });

This way, all tables will use the same name as the model name.

Providing the table name directly

You can simply tell Sequelize the name of the table directly as well:

  1. sequelize.define('User', {
  2. // ... (attributes)
  3. }, {
  4. tableName: 'Employees'
  5. });

Model synchronization

When you define a model, you’re telling Sequelize a few things about its table in the database. However, what if the table actually doesn’t even exist in the database? What if it exists, but it has different columns, less columns, or any other difference?

This is where model synchronization comes in. A model can be synchronized with the database by calling model.sync(options), an asynchronous function (that returns a Promise). With this call, Sequelize will automatically perform an SQL query to the database. Note that this changes only the table in the database, not the model in the JavaScript side.

  • User.sync() - This creates the table if it doesn’t exist (and does nothing if it already exists)
  • User.sync({ force: true }) - This creates the table, dropping it first if it already existed
  • User.sync({ alter: true }) - This checks what is the current state of the table in the database (which columns it has, what are their data types, etc), and then performs the necessary changes in the table to make it match the model.

Example:

  1. await User.sync({ force: true });
  2. console.log("The table for the User model was just (re)created!");

Synchronizing all models at once

You can use sequelize.sync() to automatically synchronize all models. Example:

  1. await sequelize.sync({ force: true });
  2. console.log("All models were synchronized successfully.");

Dropping tables

To drop the table related to a model:

  1. await User.drop();
  2. console.log("User table dropped!");

To drop all tables:

  1. await sequelize.drop();
  2. console.log("All tables dropped!");

Database safety check

As shown above, the sync and drop operations are destructive. Sequelize acceps a match option as an additional safety check, which receives a RegExp:

  1. // This will run .sync() only if database name ends with '_test'
  2. sequelize.sync({ force: true, match: /_test$/ });

Synchronization in production

As shown above, sync({ force: true }) and sync({ alter: true }) can be destructive operations. Therefore, they are not recommended for production-level software. Instead, synchronization should be done with the advanced concept of Migrations, with the help of the Sequelize CLI.

Timestamps

By default, Sequelize automatically adds the fields createdAt and updatedAt to every model, using the data type DataTypes.DATE. Those fields are automatically managed as well - whenever you use Sequelize to create or update something, those fields will be set correctly. The createdAt field will contain the timestamp representing the moment of creation, and the updatedAt will contain the timestamp of the latest update.

Note: This is done in the Sequelize level (i.e. not done with SQL triggers). This means that direct SQL queries (for example queries performed without Sequelize by any other means) will not cause these fields to be updated automatically.

This behavior can be disabled for a model with the timestamps: false option:

  1. sequelize.define('User', {
  2. // ... (attributes)
  3. }, {
  4. timestamps: false
  5. });

It is also possible to enable only one of createdAt/updatedAt, and to provide a custom name for these columns:

  1. class Foo extends Model {}
  2. Foo.init({ /* attributes */ }, {
  3. sequelize,
  4. // don't forget to enable timestamps!
  5. timestamps: true,
  6. // I don't want createdAt
  7. createdAt: false,
  8. // I want updatedAt to actually be called updateTimestamp
  9. updatedAt: 'updateTimestamp'
  10. });

Column declaration shorthand syntax

If the only thing being specified about a column is its data type, the syntax can be shortened:

  1. // This:
  2. sequelize.define('User', {
  3. name: {
  4. type: DataTypes.STRING
  5. }
  6. });
  7. // Can be simplified to:
  8. sequelize.define('User', { name: DataTypes.STRING });

Default Values

By default, Sequelize assumes that the default value of a column is NULL. This behavior can be changed by passing a specific defaultValue to the column definition:

  1. sequelize.define('User', {
  2. name: {
  3. type: DataTypes.STRING,
  4. defaultValue: "John Doe"
  5. }
  6. });

Some special values, such as Sequelize.NOW, are also accepted:

  1. sequelize.define('Foo', {
  2. bar: {
  3. type: DataTypes.DATETIME,
  4. defaultValue: Sequelize.NOW
  5. // This way, the current date/time will be used to populate this column (at the moment of insertion)
  6. }
  7. });

Data Types

Every column you define in your model must have a data type. Sequelize provides a lot of built-in data types. To access a built-in data type, you must import DataTypes:

  1. const { DataTypes } = require("sequelize"); // Import the built-in data types

Strings

  1. DataTypes.STRING // VARCHAR(255)
  2. DataTypes.STRING(1234) // VARCHAR(1234)
  3. DataTypes.STRING.BINARY // VARCHAR BINARY
  4. DataTypes.TEXT // TEXT
  5. DataTypes.TEXT('tiny') // TINYTEXT
  6. DataTypes.CITEXT // CITEXT PostgreSQL and SQLite only.

Boolean

  1. DataTypes.BOOLEAN // TINYINT(1)

Numbers

  1. DataTypes.INTEGER // INTEGER
  2. DataTypes.BIGINT // BIGINT
  3. DataTypes.BIGINT(11) // BIGINT(11)
  4. DataTypes.FLOAT // FLOAT
  5. DataTypes.FLOAT(11) // FLOAT(11)
  6. DataTypes.FLOAT(11, 10) // FLOAT(11,10)
  7. DataTypes.REAL // REAL PostgreSQL only.
  8. DataTypes.REAL(11) // REAL(11) PostgreSQL only.
  9. DataTypes.REAL(11, 12) // REAL(11,12) PostgreSQL only.
  10. DataTypes.DOUBLE // DOUBLE
  11. DataTypes.DOUBLE(11) // DOUBLE(11)
  12. DataTypes.DOUBLE(11, 10) // DOUBLE(11,10)
  13. DataTypes.DECIMAL // DECIMAL
  14. DataTypes.DECIMAL(10, 2) // DECIMAL(10,2)

Unsigned & Zerofill integers - MySQL/MariaDB only

In MySQL and MariaDB, the data types INTEGER, BIGINT, FLOAT and DOUBLE can be set as unsigned or zerofill (or both), as follows:

  1. DataTypes.INTEGER.UNSIGNED
  2. DataTypes.INTEGER.ZEROFILL
  3. DataTypes.INTEGER.UNSIGNED.ZEROFILL
  4. // You can also specify the size i.e. INTEGER(10) instead of simply INTEGER
  5. // Same for BIGINT, FLOAT and DOUBLE

Dates

  1. DataTypes.DATE // DATETIME for mysql / sqlite, TIMESTAMP WITH TIME ZONE for postgres
  2. DataTypes.DATE(6) // DATETIME(6) for mysql 5.6.4+. Fractional seconds support with up to 6 digits of precision
  3. DataTypes.DATEONLY // DATE without time

UUIDs

For UUIDs, use DataTypes.UUID. It becomes the UUID data type for PostgreSQL and SQLite, and CHAR(36) for MySQL. Sequelize can generate UUIDs automatically for these fields, simply use Sequelize.UUIDV1 or Sequelize.UUIDV4 as the default value:

  1. {
  2. type: DataTypes.UUID,
  3. defaultValue: Sequelize.UUIDV4 // Or Sequelize.UUIDV1
  4. }

Others

There are other data types, covered in a separate guide.

Column Options

When defining a column, apart from specifying the type of the column, and the allowNull and defaultValue options mentioned above, there are a lot more options that can be used. Some examples are below.

  1. const { Model, DataTypes, Deferrable } = require("sequelize");
  2. class Foo extends Model {}
  3. Foo.init({
  4. // instantiating will automatically set the flag to true if not set
  5. flag: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true },
  6. // default values for dates => current time
  7. myDate: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
  8. // setting allowNull to false will add NOT NULL to the column, which means an error will be
  9. // thrown from the DB when the query is executed if the column is null. If you want to check that a value
  10. // is not null before querying the DB, look at the validations section below.
  11. title: { type: DataTypes.STRING, allowNull: false },
  12. // Creating two objects with the same value will throw an error. The unique property can be either a
  13. // boolean, or a string. If you provide the same string for multiple columns, they will form a
  14. // composite unique key.
  15. uniqueOne: { type: DataTypes.STRING, unique: 'compositeIndex' },
  16. uniqueTwo: { type: DataTypes.INTEGER, unique: 'compositeIndex' },
  17. // The unique property is simply a shorthand to create a unique constraint.
  18. someUnique: { type: DataTypes.STRING, unique: true },
  19. // Go on reading for further information about primary keys
  20. identifier: { type: DataTypes.STRING, primaryKey: true },
  21. // autoIncrement can be used to create auto_incrementing integer columns
  22. incrementMe: { type: DataTypes.INTEGER, autoIncrement: true },
  23. // You can specify a custom column name via the 'field' attribute:
  24. fieldWithUnderscores: { type: DataTypes.STRING, field: 'field_with_underscores' },
  25. // It is possible to create foreign keys:
  26. bar_id: {
  27. type: DataTypes.INTEGER,
  28. references: {
  29. // This is a reference to another model
  30. model: Bar,
  31. // This is the column name of the referenced model
  32. key: 'id',
  33. // With PostgreSQL, it is optionally possible to declare when to check the foreign key constraint, passing the Deferrable type.
  34. deferrable: Deferrable.INITIALLY_IMMEDIATE
  35. // Options:
  36. // - `Deferrable.INITIALLY_IMMEDIATE` - Immediately check the foreign key constraints
  37. // - `Deferrable.INITIALLY_DEFERRED` - Defer all foreign key constraint check to the end of a transaction
  38. // - `Deferrable.NOT` - Don't defer the checks at all (default) - This won't allow you to dynamically change the rule in a transaction
  39. }
  40. },
  41. // Comments can only be added to columns in MySQL, MariaDB, PostgreSQL and MSSQL
  42. commentMe: {
  43. type: DataTypes.INTEGER,
  44. comment: 'This is a column name that has a comment'
  45. }
  46. }, {
  47. sequelize,
  48. modelName: 'foo',
  49. // Using `unique: true` in an attribute above is exactly the same as creating the index in the model's options:
  50. indexes: [{ unique: true, fields: ['someUnique'] }]
  51. });

Taking advantage of Models being classes

The Sequelize models are ES6 classes. You can very easily add custom instance or class level methods.

  1. class User extends Model {
  2. static classLevelMethod() {
  3. return 'foo';
  4. }
  5. instanceLevelMethod() {
  6. return 'bar';
  7. }
  8. getFullname() {
  9. return [this.firstname, this.lastname].join(' ');
  10. }
  11. }
  12. User.init({
  13. firstname: Sequelize.TEXT,
  14. lastname: Sequelize.TEXT
  15. }, { sequelize });
  16. console.log(User.classLevelMethod()); // 'foo'
  17. const user = User.build({ firstname: 'Jane', lastname: 'Doe' });
  18. console.log(user.instanceLevelMethod()); // 'bar'
  19. console.log(user.getFullname()); // 'Jane Doe'