본문 바로가기
sequelize_공식문서 번역

Model Basics

by 시계의온도 2020. 9. 1.

2020.09.01 일 번역글 작성. 

해당 글은 기술에 대한 지식(부트캠프 직장인반 5개월정도) 와 영어(오픽 IH) 에 수준으로 학습을 위해 단순 번역한 것이므로 정확하지 않을 수 있습니다. 잘못된 점이 있다면 댓글 피드백 주시면 감사하겠습니다. 확인 후 수정하겠습니다!

 

원본: https://sequelize.org/master/manual/model-basics.html

 

Manual | Sequelize

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.

sequelize.org

 

Model Basics

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

이 튜토리얼에서 Sequelize에서 models가 무엇이고 어떻게 사용하는지 배울 수 있을 것입니다. 

Concept

Models are the essence of Sequelize.

모델은 sequelize의 핵심입니다.

 

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

model은 본인의 database의 table을 나타내는 추상적인 개념입니다.

 

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).

model은 Sequelize에게 database의 table명이나, 어떤 columns를 가지고 있는지를 나타내는 몇가지 entity전달해줍니다.

 

A model in Sequelize has a name.

Sequelize에 있는 모델은 이름을 가지고 있습니다. 

 

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.

보통, 모델들은 단수형이름을 가지는데(User같은), 테이블들은 복수형 이름을 가집니다(Uers같은). 그치만 구성하기 나름입니다. 

Model Definition

Models can be defined in two equivalent ways in Sequelize:

모델은 Sequelize에서 두가지 방식으로 나타낼 수 있습니다. 

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

모델이 정의되고 나면, sequelize.models에서 모델명으로 사용할 수 있습니다.

[*개인적인 생각으로는  sequelize 객체에, models키로 모델명이 들어가는 방식인것 같습니다. 나중에 터미널에서 console에 찍히는 형태를 보면 객체형태고, url모델 생성후 controller/index.js파일 (= 모델을 사용하고자하는 별도의 js파일)에서

const {url:URLModel} = require('../../models')

구조분해 할당으로 받아와서 URLModel을 사용할 수 있습니다.] 

 

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.

예시로 배울 수 있도록, 우리는 우리가 firstName과 lastName을 가진 users를나타내는 모델을 만들고 싶어한다고 생각합시다. 

 

We want our model to be called User, and the table it represents is called Users in the database.

우리는 모델은 User라고 하고, 그 모델이 나타내는 Database의 table은 Users라고 할 것 입니다.  

 

Both ways to define this model are shown below.

모델을 정의하는 두가지 방식은 아래에서 보실 수 있습니다.

 

After being defined, we can access our model with sequelize.models.User.

정의되고 나면, 우리는 sequelize.models.User. 로 모델에 접근할 수 있습니다. 

Using sequelize.define:

const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory:');
[* sequelize 인스턴스를 생성한다 
   ref: https://jeonghwan-kim.github.io/dev/2020/07/06/sequelize-model.html
   인스턴스의 개념을 한번 다시 생각해보자면, 인스턴스는 클래스로 생성된 세부객체로 같은 것으로 '차'라는 클래스
   의 인스턴스는 아반떼, BMW,산타페로 정의 할 수 있다.
   let avante = new car('지정한 속성들')
 ]

const User = sequelize.define('User', {
  // Model attributes are defined here
  // 모델 attributes은 여기서 정의합니다
  firstName: {
    type: DataTypes.STRING,
    allowNull: false
  },
  lastName: {
    type: DataTypes.STRING
    // allowNull defaults to true
  }
}, {
  // Other model options go here
  // 다른 모델 옵션들은 여기서 사용 
});

// `sequelize.define` also returns the model
// `sequelize.define`은 모델을 리턴합니다. 

console.log(User === sequelize.models.User); // true

Extending Model

const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory');

class User extends Model {}

User.init({
  // Model attributes are defined here
  // 모델 attributes 는 여기서 정의한다 
  firstName: {
    type: DataTypes.STRING,
    allowNull: false
  },
  lastName: {
    type: DataTypes.STRING
    // allowNull defaults to true
  }
}, {
  // Other model options go here
  sequelize, 
  // We need to pass the connection instance
  // 데이터베이스 connection
  modelName: 'User' // We need to choose the model name
});

// the defined model is the class itself
// 클래스는 정의한 모델이다.
console.log(User === sequelize.models.User); // true

 

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

내부적으로, sequelize.define Model.init을 호출하므로, 두가지 방식은 본질적으로 동일합니다. 

Table name inference  테이블 이름 추론

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

위에 있는 두가지 방법을 관찰해보면, 테이블명(Users)는 전혀 명시적으로 정의되어 있지 않습니다. 

 

However, the model name was given (User).

그러나 모델의 이름은 (User)로 주어져 있습니다. 

 

By default, when the table name is not given, Sequelize automatically pluralizes the model name and uses that as the table name.

기본적으로 테이블 이름이 주어지지 않은 경우, Sequelize는 모델 이름을 자동으로 복수화하여 테이블 이름으로 사용합니다.

 

This pluralization is done under the hood by a library called inflection, so that irregular plurals (such as person -> people) are computed correctly.

이러한 복수화는 inflection 라이브러리에서 이루어집니다. 그래서 불규칙적인 복수화 ( person -> people같은) 것도 정확하게 계산됩니다. 

 

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.

Sequelize가 수행하는 자동 복수화를 freezeTableName: true 옵션을 사용해서 멈출 수 있습니다.

 

This way, Sequelize will infer the table name to be equal to the model name, without any modifications:

이렇게 하면 수정없이, Sequelize는 테이블명이 모델이름이랑 똑같다고 생각할 것입니다. 

sequelize.define('User', {
  // ... (attributes)
}, {
  freezeTableName: true
});

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

위에 있는 예시는 User로 이름지어진 테이블을 가리키는 User로 이름지어진 모델을 만들것입니다.  

 

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:

테이블 이름을 바로 Sequelize에 직접 전달 할 수도 있습니다: 

sequelize.define('User', {
  // ... (attributes)
}, {
  tableName: 'Employees'
});

Model synchronization  모델 동기화

When you define a model, you're telling Sequelize a few things about its table in the database.

모델을 정의할때, 데이터베이스에 있는 테이블에 대한 몇가지를 Sequelize에 얘기했을 것입니다. 

 

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?

존재하지만, 다른 columns, 적은 columns, 혹은 다른 차이점이 있다면? 

 

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).

모델은 프로미스를 리턴하는 비동기 함수인 model.sync(options) 을 호출함으로써 데이터베이스와 동기화될 수 있습니다. 

 

With this call, Sequelize will automatically perform an SQL query to the database.

이 호출을 통해서, Sequelize 자동으로 데이터베이스에 대한 SQL query를 수행할 것입니다.  

 

Note that this changes only the table in the database, not the model in the JavaScript side.

이렇게 하면 JavaScript의 모델이 아니라 데이터베이스의 테이블만 변경된다는 점에 유의하세요. 

 

  • User.sync() - This creates the table if it doesn't exist (and does nothing if it already exists)
  • User.sync() - 테이블이 없으면 테이블을 생성합니다. ( 이미 존재하면 아무것도 안합니다.) 
  • User.sync({ force: true }) - This creates the table, dropping it first if it already existed
  • User.sync({ force:true }) - 테이블을 생성하고, 이미 존재하고 있으면 기존테이블을 삭제합니다.  
  • 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.
  • User.sync({ alter: true})  - 데이터베이스 테이블의 현재 상태( 어떤 colums를 가졌는지, 데이터 타입이 어떤지. 등등) 를 체크하고, 모델과 맞도록 테이블을 수정합니다. 

Example:

await User.sync({ force: true });
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. 

모든 모델들을 자동으로 동기화하기 위해서 sequelize.sync()을 사용할 수 있습니다. 

 

Example:

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

Dropping tables  테이블삭제하기 

To drop the table related to a model:

모델과 관련된 테이블을 삭제하기: 

 

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

 

To drop all tables:

모든 테이블 삭제하기: 

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

 

Database safety check  데이터베이스 안전성 확인

As shown above, the sync and drop operations are destructive.

위에서 볼 수 있듯이, sync과 drop 연산은 파괴적입니다. 

 

Sequelize acceps a match option as an additional safety check, which receives a RegExp:

Sequelize는 부가적인 안전 검사로  RegExp를 받는  match option을 사용합니다. 

 

// This will run .sync() only if database name ends with '_test'
// 데이터 베이스 이름이 '_test'로 끝날때만 동기화를 작동합니다. 

sequelize.sync({ force: true, match: /_test$/ });

Synchronization in production 프로덕션에서 동기화

As shown above, sync({ force: true }) and sync({ alter: true }) can be destructive operations. 

위에서 봤듯이, sync({ force: true })와 sync({ alter: true })은  파괴적인 작업일 있습니다.

 

Therefore, they are not recommended for production-level software.

그러므로, production-level software에서는 권장하지 않습니다.

 

Instead, synchronization should be done with the advanced concept of Migrations, with the help of the Sequelize CLI.

대신, 동기화는 마이그레이션의 고급 개념으로서 진행되어야 합니다. Sequelize CLI.의 도움을 받아서. 

Timestamps  

By default, Sequelize automatically adds the fields createdAt and updatedAt to every model, using the data type DataTypes.DATE.

기본적으로, Sequelize는 data type DataTypes.DATE.을 사용해 자동으로 createdAt과 updatedAt 필드를 모든 모델에 추가합니다.

 

Those fields are automatically managed as well - whenever you use Sequelize to create or update something, those fields will be set correctly.

이 필드들은 자동으로 잘 관리됩니다 - Sequelize를 사용해서 무언가를 생성하거나 업데이트 할때마다, 이 필드들은 정확하게 세팅됩니다.

 

The createdAt field will contain the timestamp representing the moment of creation, and the updatedAt will contain the timestamp of the latest update.

createdAt 필드는 생성되는 순간을 나타내는 타임스탬프를 포함하고 있고, updatedAt은 가장 마지막 업데이트된 타임스탬프를 포함하고 있습니다.

 

Note: This is done in the Sequelize level (i.e. not done with SQL triggers).

확인: 이건 Sequelize level에서 이루어 집니다. 

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.

이것은 direact SQL queries ( 예를 들어 다른 수단에 의해 Sequelize 없이 수행되는 쿼리)는 이 필드들을 자동으로 업데이트 하지 않는 것을 의미합니다.

 

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

모델에서 타임스템프를 사용하지 않도록  timestamps: false 으로 설정할 수 있습니다:

sequelize.define('User', {
  // ... (attributes)
}, {
  timestamps: false
});

 

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

createdAt/updatedAt 둘 중 하나만 사용하는 것도 가능하고, 이 columns에 커스텀된 이름을 제공하는 것도 가능합니다:

 

class Foo extends Model {}
Foo.init({ /* attributes */ }, {
  sequelize,

  // don't forget to enable timestamps!
  timestamps: true,

  // I don't want createdAt
  createdAt: false,

  // I want updatedAt to actually be called updateTimestamp
  updatedAt: 'updateTimestamp'
});

Column declaration shorthand syntax  컬럼선언 단축 문법

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

데이터 타입 한개만 특정해야 한다면, 문법은 단순화 할 수 있습니다.

 

// This:
sequelize.define('User', {
  name: {
    type: DataTypes.STRING
  }
});

// Can be simplified to:
sequelize.define('User', { name: DataTypes.STRING });

Default Values  기본값

By default, Sequelize assumes that the default value of a column is NULL.

기본적으로, Sequelize는 기본값이 NULL이라고 가정합니다.

This behavior can be changed by passing a specific defaultValue to the column definition:

column definition에 특정한 defaultValue를 전달해서 바꿀 수 있습니다.

sequelize.define('User', {
  name: {
    type: DataTypes.STRING,
    defaultValue: "John Doe"
  }
});

 

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

Sequelize.NOW 같은 특별한 값들도, 가능합니다.

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

Data Types 데이터타입

Every column you define in your model must have a data type.

모델의 정의한 모든 column은 데이터 타입을 가져야 한다. 

Sequelize provides a lot of built-in data types.

Sequelize는 내장된 데이터 타입들을 제공한다. 

To access a built-in data type, you must import DataTypes:

내장된 데이터 타입을 불러오려면, DataTypes를 import해야 한다. 

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

Strings

DataTypes.STRING             // VARCHAR(255)
DataTypes.STRING(1234)       // VARCHAR(1234)
DataTypes.STRING.BINARY      // VARCHAR BINARY
DataTypes.TEXT               // TEXT
DataTypes.TEXT('tiny')       // TINYTEXT
DataTypes.CITEXT             // CITEXT          PostgreSQL and SQLite only.

Boolean

DataTypes.BOOLEAN            // TINYINT(1)

Numbers

DataTypes.INTEGER            // INTEGER
DataTypes.BIGINT             // BIGINT
DataTypes.BIGINT(11)         // BIGINT(11)

DataTypes.FLOAT              // FLOAT
DataTypes.FLOAT(11)          // FLOAT(11)
DataTypes.FLOAT(11, 10)      // FLOAT(11,10)

DataTypes.REAL               // REAL            PostgreSQL only.
DataTypes.REAL(11)           // REAL(11)        PostgreSQL only.
DataTypes.REAL(11, 12)       // REAL(11,12)     PostgreSQL only.

DataTypes.DOUBLE             // DOUBLE
DataTypes.DOUBLE(11)         // DOUBLE(11)
DataTypes.DOUBLE(11, 10)     // DOUBLE(11,10)

DataTypes.DECIMAL            // DECIMAL
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:

MySQL 하고 MariaDB에서는 데이터타입 INTEGER, BIGINT, FLOAT and DOUBLE 은 아래처럼 unsigned or zerofill (or both)할수있다.

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

Dates

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

UUIDs

For UUIDs, use DataTypes.UUID.

UUIDs를 위해서는 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:

{ type: DataTypes.UUID, defaultValue: Sequelize.UUIDV4 // Or Sequelize.UUIDV1 }

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.

컬럼을 정의할때, 컬럼의 type을 정의하는 것 외에, 그리고 위에서 언급된 allowNulldefaultValue  옵션들 외에, 사용할 수 있는 많은 옵션들이 있습니다. 

 

Some examples are below.

몇몇 예시들이 아래 있습니다.

const { Model, DataTypes, Deferrable } = require("sequelize");

class Foo extends Model {}
Foo.init({
  // instantiating will automatically set the flag to true if not set
  flag: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true },

  // default values for dates => current time
  myDate: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },

  // setting allowNull to false will add NOT NULL to the column, which means an error will be
  // thrown from the DB when the query is executed if the column is null. If you want to check that a value
  // is not null before querying the DB, look at the validations section below.
  title: { type: DataTypes.STRING, allowNull: false },

  // Creating two objects with the same value will throw an error. The unique property can be either a
  // boolean, or a string. If you provide the same string for multiple columns, they will form a
  // composite unique key.
  uniqueOne: { type: DataTypes.STRING,  unique: 'compositeIndex' },
  uniqueTwo: { type: DataTypes.INTEGER, unique: 'compositeIndex' },

  // The unique property is simply a shorthand to create a unique constraint.
  someUnique: { type: DataTypes.STRING, unique: true },

  // Go on reading for further information about primary keys
  identifier: { type: DataTypes.STRING, primaryKey: true },

  // autoIncrement can be used to create auto_incrementing integer columns
  incrementMe: { type: DataTypes.INTEGER, autoIncrement: true },

  // You can specify a custom column name via the 'field' attribute:
  fieldWithUnderscores: { type: DataTypes.STRING, field: 'field_with_underscores' },

  // It is possible to create foreign keys:
  bar_id: {
    type: DataTypes.INTEGER,

    references: {
      // This is a reference to another model
      model: Bar,

      // This is the column name of the referenced model
      key: 'id',

      // With PostgreSQL, it is optionally possible to declare when to check the foreign key constraint, passing the Deferrable type.
      deferrable: Deferrable.INITIALLY_IMMEDIATE
      // Options:
      // - `Deferrable.INITIALLY_IMMEDIATE` - Immediately check the foreign key constraints
      // - `Deferrable.INITIALLY_DEFERRED` - Defer all foreign key constraint check to the end of a transaction
      // - `Deferrable.NOT` - Don't defer the checks at all (default) - This won't allow you to dynamically change the rule in a transaction
    }
  },

  // Comments can only be added to columns in MySQL, MariaDB, PostgreSQL and MSSQL
  commentMe: {
    type: DataTypes.INTEGER,
    comment: 'This is a column name that has a comment'
  }
}, {
  sequelize,
  modelName: 'foo',

  // Using `unique: true` in an attribute above is exactly the same as creating the index in the model's options:
  indexes: [{ unique: true, fields: ['someUnique'] }]
});

Taking advantage of Models being classes 클래스를 사용했을 때 이점

The Sequelize models are ES6 classes.

Sequelize models은 ES6 클래스입니다. 

 

You can very easily add custom instance or class level methods.

굉장히 쉽게 custom instance or class level methods를 추가할 수 있습니다. 

class User extends Model {
  static classLevelMethod() {
    return 'foo';
  }
  instanceLevelMethod() {
    return 'bar';
  }
  getFullname() {
    return [this.firstname, this.lastname].join(' ');
  }
}
User.init({
  firstname: Sequelize.TEXT,
  lastname: Sequelize.TEXT
}, { sequelize });

console.log(User.classLevelMethod()); // 'foo'
const user = User.build({ firstname: 'Jane', lastname: 'Doe' });
console.log(user.instanceLevelMethod()); // 'bar'
console.log(user.getFullname()); // 'Jane Doe'

댓글