Sequelize(2) 定義表格

定義

定義模型與表之間的映射,使用 define 方法.

Sequelize 會自動增加 createdAtupdated 屬性,這樣能知道一個實例的創(chuàng)建時間和最終修改時間.如果不想自動生成,可以到configuration去看如何實現(xiàn).

var Project = sequelize.define('project', {
  title: Sequelize.STRING,
  description: Sequelize.TEXT
})

var Task = sequelize.define('task', {
  title: Sequelize.STRING,
  description: Sequelize.TEXT,
  deadline: Sequelize.DATE
})

還可以為每一個列增加一些可選屬性

var Foo = sequelize.define('foo', {
 // 自動設置默認值為 true
 flag: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true},

 //  日期默認值 => 當前時間
 myDate: { type: Sequelize.DATE, defaultValue: Sequelize.NOW },

 // 設置列的 allowNull為 false 將會為該列增加 非空 屬性
 // 在查詢數(shù)據庫之前想檢車一個值是否為 空 ,看 validation 節(jié)
 title: { type: Sequelize.STRING, allowNull: false},
 
 // 創(chuàng)建兩個擁有相同屬性的值會拋出一個錯誤
 // 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.
 someUnique: {type: Sequelize.STRING, unique: true},
 uniqueOne: { type: Sequelize.STRING,  unique: 'compositeIndex'},
 uniqueTwo: { type: Sequelize.INTEGER, unique: 'compositeIndex'}
 
 // unique 屬性同時也是創(chuàng)建一個 unique 索引 的簡寫
 someUnique: {type: Sequelize.STRING, unique: true}
 
 // 跟下面的兩句定義語句等價
 {someUnique: {type: Sequelize.STRING}},
 {indexes: [{unique: true, fields: ['someUnique']}]}

 // 主碼
 identifier: { type: Sequelize.STRING, primaryKey: true},
 
 // 自增
 incrementMe: { type: Sequelize.INTEGER, autoIncrement: true },

 // 注釋,只有 MySQL 和 PG 可以使用
 // Comments can be specified for each field for MySQL and PG
 hasComment: { type: Sequelize.INTEGER, comment: "I'm a comment!" },
 
 // 在模型中的名字是小駝峰,在表中的列名可以用 field 屬性來指定
 fieldWithUnderscores: { type: Sequelize.STRING, field: "field_with_underscores" },

 // 創(chuàng)建外碼
 bar_id: {
   type: Sequelize.INTEGER,

   references: {
     // This is a reference to another model
     model: Bar,
     //被引用模型的  列名  (是列名,即 field 名)
     key: 'id',
     // 檢查外碼約束,只支持 PostgreSQL .
     deferrable: Sequelize.Deferrable.INITIALLY_IMMEDIATE
   }
 }
})

數(shù)據類型

更詳細的可以上 DataTypes 看一看

Sequelize.STRING                      // VARCHAR(255)
Sequelize.STRING(1234)                // VARCHAR(1234)
Sequelize.STRING.BINARY               // VARCHAR BINARY
Sequelize.TEXT                        // TEXT
Sequelize.TEXT('tiny')                // TINYTEXT

Sequelize.INTEGER                     // INTEGER
Sequelize.BIGINT                      // BIGINT
Sequelize.BIGINT(11)                  // BIGINT(11)

Sequelize.FLOAT                       // FLOAT
Sequelize.FLOAT(11)                   // FLOAT(11)
Sequelize.FLOAT(11, 12)               // FLOAT(11,12)

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

Sequelize.DOUBLE                      // DOUBLE
Sequelize.DOUBLE(11)                  // DOUBLE(11)
Sequelize.DOUBLE(11, 12)              // DOUBLE(11,12)

Sequelize.DECIMAL                     // DECIMAL
Sequelize.DECIMAL(10, 2)              // DECIMAL(10,2)

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

Sequelize.ENUM('value 1', 'value 2')  // An ENUM with allowed values 'value 1' and 'value 2'
Sequelize.ARRAY(Sequelize.TEXT)       // Defines an array. PostgreSQL only.

Sequelize.JSON                        // JSON column. PostgreSQL only.
Sequelize.JSONB                       // JSONB column. PostgreSQL only.

Sequelize.BLOB                        // BLOB (bytea for PostgreSQL)
Sequelize.BLOB('tiny')                // TINYBLOB (bytea for PostgreSQL. Other options are medium and long)

Sequelize.UUID                        // UUID datatype for PostgreSQL and SQLite, CHAR(36) BINARY for MySQL (use defaultValue: Sequelize.UUIDV1 or Sequelize.UUIDV4 to make sequelize generate the ids automatically)


Sequelize.GEOMETRY                    // Spatial column.  PostgreSQL (with PostGIS) or MySQL only.
Sequelize.GEOMETRY('POINT')           // Spatial column with geomerty type.  PostgreSQL (with PostGIS) or MySQL only.
Sequelize.GEOMETRY('POINT', 4326)     // Spatial column with geomerty type and SRID.  PostgreSQL (with PostGIS) or MySQL only.

integer, bigint, float 和 double 同樣支持 unsigned 和 zerofill 約束

Sequelize.INTEGER.UNSIGNED              // INTEGER UNSIGNED
Sequelize.INTEGER(11).UNSIGNED          // INTEGER(11) UNSIGNED
Sequelize.INTEGER(11).ZEROFILL          // INTEGER(11) ZEROFILL
Sequelize.INTEGER(11).ZEROFILL.UNSIGNED // INTEGER(11) UNSIGNED ZEROFILL
Sequelize.INTEGER(11).UNSIGNED.ZEROFILL // INTEGER(11) UNSIGNED ZEROFILL

對象標記的用法

// for enums:
sequelize.define('model', {
  states: {
    type:   Sequelize.ENUM,
    values: ['active', 'pending', 'deleted']
  }
})

Getters & Setters 方法

在模型中定義'對象-屬性'的 getter 和 setter 方法是可能的,可以被用來保護與數(shù)據庫列相映射的屬性,還可以定義一些屬性
Getters 和 Setters 能以下面兩種方式定義

  • 作為單個屬性定義的一部分
  • 作為模型可選的一部分

N.B: If a getter or setter is defined in both places then the function found in the relevant property definition will always take precedence.

定義為屬性的一部分

var Employee = sequelize.define('employee', {
  name:  {
    type     : Sequelize.STRING,
    allowNull: false,
    get      : function()  {
      var title = this.getDataValue('title');
      // 'this' 允許你去獲得實例的屬性
      return this.getDataValue('name') + ' (' + title + ')';
    },
  },
  title: {
    type     : Sequelize.STRING,
    allowNull: false,
    set      : function(val) {
      this.setDataValue('title', val.toUpperCase());
    }
  }
});

Employee
  .create({ name: 'John Doe', title: 'senior engineer' })
  .then(function(employee) {
    console.log(employee.get('name')); // John Doe (SENIOR ENGINEER)
    console.log(employee.get('title')); // SENIOR ENGINEER
  })

定義為模型的一部分

下面是一個在模型內定義 getter 和 setter 方法的例子. 在這個例子里,fullname 的 getter 方法是在模型內定義假屬性的一個例子
,因為 fullname 屬性不存在于數(shù)據庫模式中. 實際上,假屬性可以通過以下兩種方式來定義

  • 通過模型的 getter 方法
  • 或者通過使用帶有 VIRTUAL 數(shù)據類型的列, VIRTUAL 數(shù)據類型可以有 validation , 然而 virtual 數(shù)據類型的 getter 方法不行

注意在 fullName 的 getter 方法中引用的 this.firstNamethis.lastName 會觸發(fā)各自的 getter 方法

var Foo = sequelize.define('foo', {
  firstname: Sequelize.STRING,
  lastname: Sequelize.STRING
}, {
  getterMethods   : {
    fullName       : function()  { return this.firstname + ' ' + this.lastname }
  },
  
  setterMethods   : {
    fullName       : function(value) {
        var names = value.split(' ');
        this.setDataValue('firstname', names.slice(0, -1).join(' '));
        this.setDataValue('lastname', names.slice(-1).join(' '));
    },
  }
});

在 getter 和 setter 方法中使用的 Helper 方法

  • 獲取一個基礎屬性值 , 經常用 this.getDataValue()
  • 設置一個基礎屬性值 , 經常用 this.setDataValue()
  • 堅持使用 getter 和 setter 方法 可以保護內部數(shù)據
/* 'title' 屬性的 getter 方法*/
function(){
    return this.getDataValue('title');
}

/* 'title' 屬性的 setter 方法*/
function(){
    return this.setDataValue('title',title.toString().toLowerCase());
}

認證 (Validation)

模型認證, 可以規(guī)定模型中每個屬性的格式/內容 的認證. 其實現(xiàn)在

當進行 create,updatesave操作時,認證會自動運行.也可以在實例中手動認證

var ValidateMe = sequelize.define('foo', {
  foo: {
    type: Sequelize.STRING,
    validate: {
      is: ["^[a-z]+$",'i'],     // will only allow letters
      is: /^[a-z]+$/i,          // same as the previous example using real RegExp
      not: ["[a-z]",'i'],       // will not allow letters
      isEmail: true,            // checks for email format (foo@bar.com)
      isUrl: true,              // checks for url format (http://foo.com)
      isIP: true,               // checks for IPv4 (129.89.23.1) or IPv6 format
      isIPv4: true,             // checks for IPv4 (129.89.23.1)
      isIPv6: true,             // checks for IPv6 format
      isAlpha: true,            // will only allow letters
      isAlphanumeric: true,     // will only allow alphanumeric characters, so "_abc" will fail
      isNumeric: true,          // will only allow numbers
      isInt: true,              // checks for valid integers
      isFloat: true,            // checks for valid floating point numbers
      isDecimal: true,          // checks for any numbers
      isLowercase: true,        // checks for lowercase
      isUppercase: true,        // checks for uppercase
      notNull: true,            // won't allow null
      isNull: true,             // only allows null
      notEmpty: true,           // don't allow empty strings
      equals: 'specific value', // only allow a specific value
      contains: 'foo',          // force specific substrings
      notIn: [['foo', 'bar']],  // check the value is not one of these
      isIn: [['foo', 'bar']],   // check the value is one of these
      notContains: 'bar',       // don't allow specific substrings
      len: [2,10],              // only allow values with length between 2 and 10
      isUUID: 4,                // only allow uuids
      isDate: true,             // only allow date strings
      isAfter: "2011-11-05",    // only allow date strings after a specific date
      isBefore: "2011-11-05",   // only allow date strings before a specific date
      max: 23,                  // only allow values
      min: 23,                  // only allow values >= 23
      isArray: true,            // only allow arrays
      isCreditCard: true,       // check for valid credit card numbers

      // custom validations are also possible:
      isEven: function(value) {
        if(parseInt(value) % 2 != 0) {
          throw new Error('Only even values are allowed!')
        // we also are in the model's context here, so this.otherField
        // would get the value of otherField if it existed
        }
      }
    }
  }
});

注意當多個參數(shù)需要被傳遞到內嵌的認證函數(shù)時,多個參數(shù)應該被放在一個數(shù)組中.

isIn: [['en', 'zh']],   // check the value is one of these

不用 validator.js 提供的錯誤信息,自己定制錯誤信息

isIn: {
  args: [['en', 'zh']],
  msg: "Must be English or Chinese"
}

可以看validator.js PROJECT獲取更多細節(jié)


認證器和 allowNull

如果模型的列被設置為 allowNull:true 和 值被設置為 null的話,那認證器不會運行.

舉個栗子, 一個字符串的列長度設置為 最短為5, 但它可以存儲 null

模型認證

var Pub = Sequelize.define('pub', {
  name: { type: Sequelize.STRING },
  address: { type: Sequelize.STRING },
  latitude: {
    type: Sequelize.INTEGER,
    allowNull: true,
    defaultValue: null,
    validate: { min: -90, max: 90 }
  },
  longitude: {
    type: Sequelize.INTEGER,
    allowNull: true,
    defaultValue: null,
    validate: { min: -180, max: 180 }
  },
}, {


  //在這里對模型進行驗證,只有 latitude 和 longtitude 同時被給予或都為空時成立
  validate: {
    bothCoordsOrNone: function() {
      if ((this.latitude === null) !== (this.longitude === null)) {
        throw new Error('Require either both latitude and longitude or neither')
      }
    }
  }
})

配置

var Bar = sequelize.define('bar', { /* bla */ }, {

  // 不增加 TIMESTAMP 屬性  (updatedAt, createdAt)
  timestamps: false,
  
  //不刪除數(shù)據庫中原有項, 增加新屬性 deletedAt 并設置為 當前日期,
  //只有 TIMESTAMP 屬性是允許的時候有效
  paranoid: true,
  
  // 不要使用駝峰式語法,用下劃線代替
  // so updatedAt will be updated_at
  underscored: true,
  
  // 不允許調整表名 ; 
  // 默認地, sequelize 會自動轉換所有傳遞的模型名字(define 的第一個參數(shù))
  // 為復數(shù)
  // 如果不想這樣,設置為 true
  freezeTableName: true,

  // 定義表名
  tableName: 'my_very_custom_table_name'
})

修改引擎

var Person = sequelize.define('person', { /* attributes */ }, {
  engine: 'MYISAM'
})

// or globally
var sequelize = new Sequelize(db, user, pw, {
  define: { engine: 'MYISAM' }
})

做注釋

var Person = sequelize.define('person', { /* attributes */ }, {
  comment: "I'm a table comment!"
})

導入

可以把對表的定義放在單一文件中,返回對象恰好跟在 import 方法中定義的一樣


  // in your server file - e.g. app.js
var Project = sequelize.import(__dirname + "/path/to/models/project")

  // 定義在 project.js 文件中已經定義完成了
  // DataTypes  與上面解釋的部分很像
module.exports = function(sequelize, DataTypes) {
  return sequelize.define("project", {
    name: DataTypes.STRING,
    description: DataTypes.TEXT
  })
}

sequelize.import('project', function(sequelize, DataTypes) {
  return sequelize.define("project", {
    name: DataTypes.STRING,
    description: DataTypes.TEXT
  })
})

數(shù)據庫同步

開始一個新項目的時候,我們沒有數(shù)據庫架構,于是我們不需要 Sequelize.

只需要說明我們的模型結構, 讓庫做剩下的部分,現(xiàn)在只支持 表的創(chuàng)建與刪除

// 只同步還沒在數(shù)據庫中的模型
// Sync all models that aren't already in the database
sequelize.sync()

// 強制同步所有數(shù)據庫的模型
sequelize.sync({force: true})

// 刪除所有表
sequelize.drop()

// 開始執(zhí)行
sequelize.[sync|drop]().then(function() {
  // woot woot
}).catch(function(error) {
  // whooops
})

因為.sync({force: true}) 是毀滅性的操作, 可以使用 match 選項去增加更多的安全檢查(正則)

// 刪除以 '_test' 結尾的詞
sequelize.sync({ force: true, match: /_test$/ });

模型的擴展

Sequelize 允許我們去給 模型和相應的實例 傳遞定制方法

var sequelize = new Sequelize('database', 'username', 'password', {
  // 其他可選的初始化可以放在這里
  define: {
    classMethods: {
      method1: function() {},
      method2: function() {}
    },
    instanceMethods: {
      method3: function() {}
    }
  }
})

// Example:
var Foo = sequelize.define('foo', { /* attributes */});
Foo.method1()
Foo.method2()
Foo.build().method3()

索引

Sequelize 支持在模型定義中增加索引, 這些索引在 Model.sync()sequelize.sync()時被創(chuàng)建.

sequelize.define('user', {}, {
  indexes: [
    // Create a unique index on email
    {
      unique: true,
      fields: ['email']
    },

    // Creates a gin index on data with the jsonb_path_ops operator
    {
      fields: ['data'],
      using: 'gin',
      operator: 'jsonb_path_ops'
    },

    // By default index name will be [table]_[fields]
    // Creates a multi column partial index
    {
      name: 'public_by_author',
      fields: ['author', 'status'],
      where: {
        status: 'public'
      }
    },

    // A BTREE index with a ordered field
    {
      name: 'title_index',
      method: 'BTREE',
      fields: ['author', {attribute: 'title', collate: 'en_US', order: 'DESC', length: 5}]
    }
  ]
})
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末然爆,一起剝皮案震驚了整個濱河市翔曲,隨后出現(xiàn)的幾起案子饭庞,更是在濱河造成了極大的恐慌,老刑警劉巖楣号,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異羹蚣,居然都是意外死亡袁翁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門秒拔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來莫矗,“玉大人,你說我怎么就攤上這事∽餮瑁” “怎么了三娩?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長妹懒。 經常有香客問我雀监,道長,這世上最難降的妖魔是什么眨唬? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任会前,我火速辦了婚禮,結果婚禮上匾竿,老公的妹妹穿的比我還像新娘瓦宜。我一直安慰自己,他們只是感情好岭妖,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布临庇。 她就那樣靜靜地躺著,像睡著了一般区转。 火紅的嫁衣襯著肌膚如雪苔巨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天废离,我揣著相機與錄音侄泽,去河邊找鬼。 笑死蜻韭,一個胖子當著我的面吹牛悼尾,可吹牛的內容都是我干的。 我是一名探鬼主播肖方,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼闺魏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了俯画?” 一聲冷哼從身側響起析桥,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎艰垂,沒想到半個月后泡仗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡猜憎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年娩怎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胰柑。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡截亦,死狀恐怖爬泥,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情崩瓤,我是刑警寧澤袍啡,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站谷遂,受9級特大地震影響葬馋,放射性物質發(fā)生泄漏卖鲤。R本人自食惡果不足惜肾扰,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蛋逾。 院中可真熱鬧集晚,春花似錦、人聲如沸区匣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亏钩。三九已至莲绰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間姑丑,已是汗流浹背蛤签。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留栅哀,地道東北人震肮。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像留拾,于是被迫代替她去往敵國和親戳晌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內容