詳細易用的 Sequelize 解讀

本文參考自 github repo demopark/sequelize-docs-Zh-CN,文章內容主要針對 mysql,其餘 db 請參考原文檔。html

在 Node.js 社區中,sequelize 是一個普遍使用的 ORM(Object Relational Mapping,對象關係映射) 框架,它支持 MySQL、PostgreSQL、SQLite 和 MSSQL 等多個數據源。mysql

Sequelize 文檔git

Getting started - 入門

安裝

// 經過 npm 安裝
npm install --save sequelize
複製代碼

還須要手動安裝對應的數據庫驅動程序:github

# 選擇對應的安裝:
$ npm install --save pg pg-hstore # Postgres
$ npm install --save mysql2
$ npm install --save mariadb
$ npm install --save sqlite3
$ npm install --save tedious # Microsoft SQL Server
複製代碼

創建鏈接

要鏈接到數據庫,你必須建立 Sequelize 實例. 這能夠經過將鏈接參數分別傳遞給 Sequelize 構造函數或傳遞單個鏈接 URI 來完成:正則表達式

const Sequelize = require('sequelize');

//方法1:單獨傳遞參數
const sequelize = new Sequelize('database', 'username', 'password', {
  host: 'localhost',
  dialect: /* 'mysql' | 'mariadb' | 'postgres' | 'mssql' 之一 */
});

// 方法2: 傳遞鏈接 URI
const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname');
複製代碼

鏈接池 (生產環境)

若是從單個進程鏈接到數據庫,則應僅建立一個 Sequelize 實例. Sequelize 將在初始化時設置鏈接池. 能夠經過構造函數的 options 參數(使用options.pool)配置此鏈接池,如如下示例所示:sql

const sequelize = new Sequelize(/* ... */, {
  // ...
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  }
});
複製代碼

若是從多個進程鏈接到數據庫,則必須爲每一個進程建立一個實例,但每一個實例應具備最大鏈接池大小,以便遵照總的最大大小.例如,若是你但願最大鏈接池大小爲 90 而且你有三個進程,則每一個進程的 Sequelize 實例的最大鏈接池大小應爲 30.數據庫

測試鏈接

.authenticate()npm

sequelize
  .authenticate()
  .then(() => {
    console.log('Connection has been established successfully.');
  })
  .catch(err => {
    console.error('Unable to connect to the database:', err);
  });
複製代碼

關閉鏈接

Sequelize 將默認保持鏈接持續,並對全部查詢使用相同的鏈接. 若是須要關閉鏈接,請調用 sequelize.close() (這是異步的並返回Promise).數組

表建模

模型是一個繼承自 Sequelize.Model 的 class,能夠用兩種方式定義,緩存

Sequelize.Model.init(attributes, options)

init

attributes
options

const Model = Sequelize.Model;
class User extends Model {}
User.init({
  // attributes
  firstName: {
    type: Sequelize.STRING,
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING
    // allowNull defaults to true
  }
}, {
  sequelize,
  modelName: 'user'
  // options
});
複製代碼

sequelize.define

const User = sequelize.define('user', {
  // attributes
  firstName: {
    type: Sequelize.STRING,
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING
    // allowNull defaults to true
  }
}, {
  // options
});
複製代碼

Sequelize 還默認爲每一個模型定義了字段 id(主鍵) , createdAtupdatedAt .

更改默認模型參數

const sequelize = new Sequelize(connectionURI, {
  define: {
    // `timestamps` 字段指定是否將建立 `createdAt` 和 `updatedAt` 字段.
    // 該值默認爲 true, 可是當前設定爲 false
    timestamps: false
  }
});

// 這裏 `timestamps` 爲 false,所以不會建立 `createdAt` 和 `updatedAt` 字段.
class Foo extends Model {}
Foo.init({ /* ... */ }, { sequelize });

// 這裏 `timestamps` 直接設置爲 true,所以將建立 `createdAt` 和 `updatedAt` 字段.
class Bar extends Model {}
Bar.init({ /* ... */ }, { sequelize, timestamps: true });

複製代碼

Dialect 方言

new Sequelize(db, username, password, options) 時,options 中須要指定 dialect。

MySQL

爲了讓 Sequelize 與 MySQL 一塊兒更好地工做,你須要安裝 mysql2@^1.5.2 或更高版本

const sequelize = new Sequelize('database', 'username', 'password', {
  dialect: 'mysql'
})
複製代碼

MariaDB

const sequelize = new Sequelize('database', 'username', 'password', {
  dialect: 'mariadb',
  dialectOptions: {connectTimeout: 1000} // mariadb 鏈接參數
})
複製代碼

or

const sequelize = new Sequelize('mariadb://user:password@example.com:9821/database')
複製代碼

SQLite

const sequelize = new Sequelize('database', 'username', 'password', {
  // sqlite!
  dialect: 'sqlite',

  // sqlite 的存儲引擎
  // - default ':memory:'
  storage: 'path/to/database.sqlite'
})
複製代碼

or

const sequelize = new Sequelize('sqlite:/home/abs/path/dbname.db')
const sequelize = new Sequelize('sqlite:relativePath/dbname.db')
複製代碼

PostgreSQL

PostgreSQL,須要兩個庫,pg@^7.0.0pg-hstore

const sequelize = new Sequelize('database', 'username', 'password', {
 // postgres!
 dialect: 'postgres'
})
複製代碼

MSSQL

安裝 tedious@^6.0.0

const sequelize = new Sequelize('database', 'username', 'password', {
  dialect: 'mssql'
})
複製代碼

Datatypes - 數據類型

CHAR

Sequelize.STRING                      // VARCHAR(255)
Sequelize.STRING(1234)                // VARCHAR(1234)
Sequelize.STRING.BINARY               // VARCHAR BINARY
Sequelize.TEXT                        // TEXT
Sequelize.TEXT('tiny')                // TINYTEXT
複製代碼

NUMBER

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

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

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

Sequelize.DECIMAL                     // DECIMAL
Sequelize.DECIMAL(10, 2)              // DECIMAL(10,2)
複製代碼

TIME

Sequelize.DATE                        // mysql / sqlite 爲 DATETIME, postgres 爲帶時區的 TIMESTAMP
Sequelize.DATE(6)                     // DATETIME(6) 適用 mysql 5.6.4+. 小數秒支持最多6位精度
Sequelize.DATEONLY                    // DATE 不帶時間.
複製代碼

BOOLEAN

Sequelize.BOOLEAN                     // TINYINT(1)
複製代碼

ENUM

Sequelize.ENUM('value 1', 'value 2')  // 一個容許值爲'value 1'和'value 2'的ENUM
複製代碼

blob

Sequelize.BLOB                        // BLOB (PostgreSQL 爲 bytea)
Sequelize.BLOB('tiny')                // TINYBLOB (PostgreSQL 爲 bytea. 其他參數是 medium 和 long)
複製代碼

GEOMETRY

Sequelize.GEOMETRY                    // Spatial 列. 僅 PostgreSQL (帶有 PostGIS) 或 MySQL.
Sequelize.GEOMETRY('POINT')           // 帶有 geometry 類型的 spatial 列. 僅 PostgreSQL (帶有 PostGIS) 或 MySQL.
Sequelize.GEOMETRY('POINT', 4326)     // 具備 geometry 類型和 SRID 的 spatial 列. 僅 PostgreSQL (帶有 PostGIS) 或 MySQL.
複製代碼

integer, bigint, floatdouble 還支持 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
複製代碼

對象表示

// 對於枚舉:
class MyModel extends Model {}
MyModel.init({
  states: {
    type: Sequelize.ENUM,
    values: ['active', 'pending', 'deleted']
  }
}, { sequelize })
複製代碼

Model definition - 模型定義

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

// Model 掛載在 Sequelize 上,
// const Sequelize = require('sequelize');
// const Model = Sequelize.Model;
class Project extends Model {}
Project.init({
  title: Sequelize.STRING,
  description: Sequelize.TEXT
}, { sequelize, modelName: 'project' });
複製代碼

Model 定義示例

class Foo extends Model {}
Foo.init({
 // 若是未賦值,則自動設置值爲 TRUE
 flag: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true},

 // 設置默認時間爲當前時間
 myDate: { type: Sequelize.DATE, defaultValue: Sequelize.NOW },

 // 將allowNull設置爲false會將NOT NULL添加到列中,
 // 這意味着當列爲空時執行查詢時將從DB拋出錯誤. 
 // 若是要在查詢DB以前檢查值不爲空,請查看下面的驗證部分.
 title: { type: Sequelize.STRING, allowNull: false},

 // 建立具備相同值的兩個對象將拋出一個錯誤. 惟一屬性能夠是布爾值或字符串.
 // 若是爲多個列提供相同的字符串,則它們將造成複合惟一鍵.
 uniqueOne: { type: Sequelize.STRING,  unique: 'compositeIndex'},
 uniqueTwo: { type: Sequelize.INTEGER, unique: 'compositeIndex'},

 // unique屬性用來建立一個惟一約束.
 someUnique: {type: Sequelize.STRING, unique: true},
 
 // 這與在模型選項中建立索引徹底相同.
 {someUnique: {type: Sequelize.STRING}},
 {indexes: [{unique: true, fields: ['someUnique']}]},

 // primaryKey用於定義主鍵.
 identifier: { type: Sequelize.STRING, primaryKey: true},

 // autoIncrement可用於建立自增的整數列
 incrementMe: { type: Sequelize.INTEGER, autoIncrement: true },

 // 你能夠經過'field'屬性指定自定義列名稱:
 fieldWithUnderscores: { type: Sequelize.STRING, field: 'field_with_underscores' },

 // 這能夠建立一個外鍵:
 bar_id: {
   type: Sequelize.INTEGER,

   references: {
     // 這是引用另外一個模型
     model: Bar,

     // 這是引用模型的列名稱
     key: 'id',

     // 這聲明何時檢查外鍵約束. 僅限PostgreSQL.
     deferrable: Sequelize.Deferrable.INITIALLY_IMMEDIATE
   }
 },

 // 僅能夠爲 MySQL,PostgreSQL 和 MSSQL 的列添加註釋
 commentMe: {
   type: Sequelize.INTEGER,

   comment: '這是一個包含註釋的列名'
 }
}, {
  sequelize,
  modelName: 'foo'
});
複製代碼

時間戳

默認狀況下,Sequelize 會將 createdAtupdatedAt 屬性添加到模型中,以便你可以知道數據庫條目什麼時候進入數據庫以及什麼時候被更新.若是不想要自動添加,則定義以下:

const sequelize = new Sequelize(connectionURI, {
  define: {
    // `timestamps` 字段指定是否將建立 `createdAt` 和 `updatedAt` 字段.
    // 該值默認爲 true, 可是當前設定爲 false
    timestamps: false
  }
});
複製代碼

若是你使用 Sequelize 遷移,則須要將 createdAtupdatedAt 字段添加到遷移定義中:

module.exports = {
  up(queryInterface, Sequelize) {
    return queryInterface.createTable('my-table', {
      id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true,
      },

      // 時間戳
      createdAt: Sequelize.DATE,
      updatedAt: Sequelize.DATE,
    })
  },
  down(queryInterface, Sequelize) {
    return queryInterface.dropTable('my-table');
  },
}
複製代碼

Getters & Setters

Getters和Setters能夠經過兩種方式定義(你能夠混合使用這兩種方式):

  • 做爲屬性定義的一部分
  • 做爲模型參數的一部分

注意: 若是在兩個地方定義了getter或setter,那麼在相關屬性定義中找到的函數始終是優先的.

定義爲屬性定義的一部分

class Employee extends Model {}
Employee.init({
  name: {
    type: Sequelize.STRING,
    allowNull: false,
    get() {
      const title = this.getDataValue('title');
      // 'this' 容許你訪問實例的屬性
      return this.getDataValue('name') + ' (' + title + ')';
    },
  },
  title: {
    type: Sequelize.STRING,
    allowNull: false,
    set(val) {
      this.setDataValue('title', val.toUpperCase());
    }
  }
}, { sequelize, modelName: 'employee' });

Employee
  .create({ name: 'John Doe', title: 'senior engineer' })
  .then(employee => {
    console.log(employee.get('name')); // John Doe (SENIOR ENGINEER)
    console.log(employee.get('title')); // SENIOR ENGINEER
  })
複製代碼

定義爲模型參數的一部分

class Foo extends Model {
  get fullName() {
    return this.firstname + ' ' + this.lastname;
  }

  set fullName(value) {
    const names = value.split(' ');
    this.setDataValue('firstname', names.slice(0, -1).join(' '));
    this.setDataValue('lastname', names.slice(-1).join(' '));
  }
}
Foo.init({
  firstname: Sequelize.STRING,
  lastname: Sequelize.STRING
}, {
  sequelize,
  modelName: 'foo'
});

// 或使用 `sequelize.define`
sequelize.define('Foo', {
  firstname: Sequelize.STRING,
  lastname: Sequelize.STRING
}, {
  getterMethods: {
    fullName() {
      return this.firstname + ' ' + this.lastname;
    }
  },

  setterMethods: {
    fullName(value) {
      const names = value.split(' ');

      this.setDataValue('firstname', names.slice(0, -1).join(' '));
      this.setDataValue('lastname', names.slice(-1).join(' '));
    }
  }
![]()
});
複製代碼

用於 getter 和 setter 定義內部的 Helper 方法

  • 檢索底層屬性值 - 老是使用 this.getDataValue()
/* 一個用於 'title' 屬性的 getter */
get() {
  return this.getDataValue('title')
}
複製代碼
  • 設置基礎屬性值 - 老是使用 this.setDataValue()
/* 一個用於 'title' 屬性的 setter */
set(title) {
  this.setDataValue('title', title.toString().toLowerCase());
}
複製代碼

屬性驗證器

class ValidateMe extends Model {}
ValidateMe.init({
  bar: {
    type: Sequelize.STRING,
    validate: {
      is: ["^[a-z]+$",'i'],     // 只容許字母
      is: /^[a-z]+$/i,          // 與上一個示例相同,使用了真正的正則表達式
      not: ["[a-z]",'i'],       // 不容許字母
      isEmail: true,            // 檢查郵件格式 (foo@bar.com)
      isUrl: true,              // 檢查鏈接格式 (http://foo.com)
      isIP: true,               // 檢查 IPv4 (129.89.23.1) 或 IPv6 格式
      isIPv4: true,             // 檢查 IPv4 (129.89.23.1) 格式
      isIPv6: true,             // 檢查 IPv6 格式
      isAlpha: true,            // 只容許字母
      isAlphanumeric: true,     // 只容許使用字母數字
      isNumeric: true,          // 只容許數字
      isInt: true,              // 檢查是否爲有效整數
      isFloat: true,            // 檢查是否爲有效浮點數
      isDecimal: true,          // 檢查是否爲任意數字
      isLowercase: true,        // 檢查是否爲小寫
      isUppercase: true,        // 檢查是否爲大寫
      notNull: true,            // 不容許爲空
      isNull: true,             // 只容許爲空
      notEmpty: true,           // 不容許空字符串
      equals: 'specific value', // 只容許一個特定值
      contains: 'foo',          // 檢查是否包含特定的子字符串
      notIn: [['foo', 'bar']],  // 檢查是否值不是其中之一
      isIn: [['foo', 'bar']],   // 檢查是否值是其中之一
      notContains: 'bar',       // 不容許包含特定的子字符串
      len: [2,10],              // 只容許長度在2到10之間的值
      isUUID: 4,                // 只容許uuids
      isDate: true,             // 只容許日期字符串
      isAfter: "2011-11-05",    // 只容許在特定日期以後的日期字符串
      isBefore: "2011-11-05",   // 只容許在特定日期以前的日期字符串
      max: 23,                  // 只容許值 <= 23
      min: 23,                  // 只容許值 >= 23
      isCreditCard: true,       // 檢查有效的信用卡號碼

      // 自定義驗證器的示例:
      isEven(value) {
        if (parseInt(value) % 2 !== 0) {
          throw new Error('Only even values are allowed!');
        }
      }
      isGreaterThanOtherField(value) {
        if (parseInt(value) <= parseInt(this.otherField)) {
          throw new Error('Bar must be greater than otherField.');
        }
      }
    }
  }
}, { sequelize });
複製代碼
class Pub extends Model {}
Pub.init({
  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 }
  },
}, {
  validate: {
    bothCoordsOrNone() {
      if ((this.latitude === null) !== (this.longitude === null)) {
        throw new Error('Require either both latitude and longitude or neither')
      }
    }
  },
  sequelize,
})
複製代碼

配置

class Bar extends Model {}
Bar.init({ /* bla */ }, {
  // 模型的名稱. 該模型將以此名稱存儲在`sequelize.models`中.
  // 在這種狀況下,默認爲類名,即Bar. 
  // 這將控制自動生成的foreignKey和關聯命名的名稱
  modelName: 'bar',
  // 不添加時間戳屬性 (updatedAt, createdAt)
  timestamps: false,

  // 不刪除數據庫條目,但將新添加的屬性deletedAt設置爲當前日期(刪除完成時). 
  // paranoid 只有在啓用時間戳時才能工做
  paranoid: true,

  // 將自動設置全部屬性的字段參數爲下劃線命名方式.
  // 不會覆蓋已經定義的字段選項
  underscored: true,

  // 禁用修改表名; 默認狀況下,sequelize將自動將全部傳遞的模型名稱(define的第一個參數)轉換爲複數. 若是你不想這樣,請設置如下內容
  freezeTableName: true,

  // 定義表的名稱
  tableName: 'my_very_custom_table_name',

  // 啓用樂觀鎖定. 啓用時,sequelize將向模型添加版本計數屬性,
  // 並在保存過期的實例時引起OptimisticLockingError錯誤.
  // 設置爲true或具備要用於啓用的屬性名稱的字符串.
    version: true,

  // Sequelize 實例
  sequelize,
})
複製代碼

若是你但願sequelize處理時間戳,但只想要其中一部分,或者但願你的時間戳被稱爲別的東西,則能夠單獨覆蓋每一個列:

class Foo extends Model {}
Foo.init({ /* bla */ }, {
  // 不要忘記啓用時間戳!
  timestamps: true,

  // 我不想要 createdAt
  createdAt: false,

  // 我想 updateAt 實際上被稱爲 updateTimestamp
  updatedAt: 'updateTimestamp',

  // 而且但願 deletedA t被稱爲 destroyTime(請記住啓用paranoid以使其工做)
  deletedAt: 'destroyTime',
  paranoid: true,

  sequelize,
})
複製代碼

你也能夠更改數據庫引擎,例如 變動到到 MyISAM, 默認值是 InnoDB.

class Person extends Model {}
Person.init({ /* attributes */ }, {
  engine: 'MYISAM',
  sequelize
})

// 或全局的
const sequelize = new Sequelize(db, user, pw, {
  define: { engine: 'MYISAM' }
})
複製代碼

能夠爲MySQL和PG中的表指定註釋

class Person extends Model {}
Person.init({ /* attributes */ }, {
  comment: "我是一個表註釋!",
  sequelize
})
複製代碼

導入

還可使用 import 方法將模型定義存儲在單個文件中. 返回的對象與導入文件的功能中定義的徹底相同. 因爲 Sequelizev1:5.0 的導入是被緩存的,因此當調用文件導入兩次或更屢次時,不會遇到問題.

// 在你的服務器文件中 - 例如 app.js
const Project = sequelize.import(__dirname + "/path/to/models/project")

// 模型已經在 /path/to/models/project.js 中定義好
// 你可能會注意到,DataTypes與上述相同
module.exports = (sequelize, DataTypes) => {
  class Project extends sequelize.Model { }
  Project.init({
    name: DataTypes.STRING,
    description: DataTypes.TEXT
  }, { sequelize });
  return Project;
}
複製代碼

import 方法也能夠接受回調做爲參數.

sequelize.import('project', (sequelize, DataTypes) => {
  class Project extends sequelize.Model {}
  Project.init({
    name: DataTypes.STRING,
    description: DataTypes.TEXT
  }, { sequelize })
  return Project;
})
複製代碼

樂觀鎖定

默認狀況下禁用樂觀鎖定,能夠經過在特定模型定義或全局模型配置中將version屬性設置爲true來啓用.

樂觀鎖定容許併發訪問模型記錄以進行編輯,並防止衝突覆蓋數據. 它經過檢查另外一個進程是否已經讀取記錄而進行更改,並在檢測到衝突時拋出一個OptimisticLockError.

Querying - 查詢

屬性

Model.findAll({
  attributes: ['foo', 'bar']
});
// SELECT foo, bar ...
複製代碼

屬性可使用嵌套數組來重命名:

Model.findAll({
  attributes: ['foo', ['bar', 'baz']]
});

// SELECT foo, bar AS baz ...
複製代碼

也可使用 sequelize.fn 來進行聚合:

Model.findAll({
  attributes: [[sequelize.fn('COUNT', sequelize.col('hats')), 'no_hats']]
});
// SELECT COUNT(hats) AS no_hats ...
複製代碼

詳細的功能函數請看:

使用聚合功能時,必須給它一個別名,以便可以從模型中訪問它. 在上面的例子中,你可使用 instance.get('no_hats') 得到帽子數量.

有時,若是你只想添加聚合,則列出模型的全部屬性可能使人厭煩:

// This is a tiresome way of getting the number of hats...
Model.findAll({
  attributes: ['id', 'foo', 'bar', 'baz', 'quz', [sequelize.fn('COUNT', sequelize.col('hats')), 'no_hats']]
});

// This is shorter, and less error prone because it still works if you add / remove attributes
Model.findAll({
  attributes: { include: [[sequelize.fn('COUNT', sequelize.col('hats')), 'no_hats']] }
});

// SELECT id, foo, bar, baz, quz, COUNT(hats) AS no_hats ...
複製代碼

一樣,它也能夠排除一些指定的表字段:

Model.findAll({
  attributes: { exclude: ['baz'] }
});
// SELECT id, foo, bar, quz ...
複製代碼

Where

能夠傳遞一個 where 對象來過濾查詢。where 一般用 attribute:value 鍵值對獲取一個對象,其中 value 能夠是匹配等式的數據或其餘運算符的鍵值對象,也能夠經過嵌套 orand 運算符的集合來生成複雜的 AND/OR 條件.

const Op = Sequelize.Op;

Post.findAll({
  where: {
    authorId: 2
  }
});
// SELECT * FROM post WHERE authorId = 2

Post.findAll({
  where: {
    authorId: 12,
    status: 'active'
  }
});
// SELECT * FROM post WHERE authorId = 12 AND status = 'active';

Post.findAll({
  where: {
    [Op.or]: [{authorId: 12}, {authorId: 13}]
  }
});
// SELECT * FROM post WHERE authorId = 12 OR authorId = 13;

Post.findAll({
  where: {
    authorId: {
      [Op.or]: [12, 13]
    }
  }
});
// SELECT * FROM post WHERE authorId = 12 OR authorId = 13;

Post.destroy({
  where: {
    status: 'inactive'
  }
});
// DELETE FROM post WHERE status = 'inactive';

Post.update({
  updatedAt: null,
}, {
  where: {
    deletedAt: {
      [Op.ne]: null
    }
  }
});
// UPDATE post SET updatedAt = null WHERE deletedAt NOT NULL;

Post.findAll({
  where: sequelize.where(sequelize.fn('char_length', sequelize.col('status')), 6)
});
// SELECT * FROM post WHERE char_length(status) = 6;
複製代碼

操做符

const Op = Sequelize.Op

[Op.and]: {a: 5}           // 且 (a = 5)
[Op.or]: [{a: 5}, {a: 6}]  // (a = 5 或 a = 6)
[Op.gt]: 6,                // id > 6
[Op.gte]: 6,               // id >= 6
[Op.lt]: 10,               // id < 10
[Op.lte]: 10,              // id <= 10
[Op.ne]: 20,               // id != 20
[Op.eq]: 3,                // = 3
[Op.not]: true,            // 不是 TRUE
[Op.between]: [6, 10],     // 在 6 和 10 之間
[Op.notBetween]: [11, 15], // 不在 11 和 15 之間
[Op.in]: [1, 2],           // 在 [1, 2] 之中
[Op.notIn]: [1, 2],        // 不在 [1, 2] 之中
[Op.like]: '%hat',         // 包含 '%hat'
[Op.notLike]: '%hat'       // 不包含 '%hat'
[Op.iLike]: '%hat'         // 包含 '%hat' (不區分大小寫) (僅限 PG)
[Op.notILike]: '%hat'      // 不包含 '%hat' (僅限 PG)
[Op.startsWith]: 'hat'     // 相似 'hat%'
[Op.endsWith]: 'hat'       // 相似 '%hat'
[Op.substring]: 'hat'      // 相似 '%hat%'
[Op.regexp]: '^[h|a|t]'    // 匹配正則表達式/~ '^[h|a|t]' (僅限 MySQL/PG)
[Op.notRegexp]: '^[h|a|t]' // 不匹配正則表達式/!~ '^[h|a|t]' (僅限 MySQL/PG)
[Op.iRegexp]: '^[h|a|t]'    // ~* '^[h|a|t]' (僅限 PG)
[Op.notIRegexp]: '^[h|a|t]' // !~* '^[h|a|t]' (僅限 PG)
[Op.like]: { [Op.any]: ['cat', 'hat']} // 包含任何數組['cat', 'hat'] - 一樣適用於 iLike 和 notLike
[Op.overlap]: [1, 2]       // && [1, 2] (PG數組重疊運算符)
[Op.contains]: [1, 2]      // @> [1, 2] (PG數組包含運算符)
[Op.contained]: [1, 2]     // <@ [1, 2] (PG數組包含於運算符)
[Op.any]: [2,3]            // 任何數組[2, 3]::INTEGER (僅限PG)

[Op.col]: 'user.organization_id' // = 'user'.'organization_id', 使用數據庫語言特定的列標識符, 本例使用 PG
複製代碼

組合

{
  rank: {
    [Op.or]: {
      [Op.lt]: 1000,
      [Op.eq]: null
    }
  }
}
// rank < 1000 OR rank IS NULL

{
  createdAt: {
    [Op.lt]: new Date(),
    [Op.gt]: new Date(new Date() - 24 * 60 * 60 * 1000)
  }
}
// createdAt < [timestamp] AND createdAt > [timestamp - 1d]

{
  [Op.or]: [
    {
      title: {
        [Op.like]: 'Boat%'
      }
    },
    {
      description: {
        [Op.like]: '%boat%'
      }
    }
  ]
}
// title LIKE 'Boat%' OR description LIKE '%boat%'
複製代碼

運算符別名

const Op = Sequelize.Op;
const operatorsAliases = {
  $gt: Op.gt
}
const connection = new Sequelize(db, user, pass, { operatorsAliases })

[Op.gt]: 6 // > 6
$gt: 6 // 等同於使用 Op.gt (> 6)
複製代碼

運算符安全性

默認狀況下,Sequelize 將使用 Symbol 運算符. 使用沒有任何別名的 Sequelize 能夠提升安全性.沒有任何字符串別名將使得運算符可能被注入的可能性降到極低,但你應該始終正確驗證和清理用戶輸入.

爲了更好的安全性,強烈建議在代碼中使用 Sequelize.Op 中的符號運算符,如 Op.and / Op.or,而不依賴於任何基於字符串的運算符,如 $and / $or. 你能夠經過設置 operatorsAliases 參數來限制應用程序所需的別名,

若是你想繼續使用全部默認別名(不包括舊版別名)而不發出警告,你能夠傳遞如下運算符參數 -

const Op = Sequelize.Op;
const operatorsAliases = {
  $eq: Op.eq,
  $ne: Op.ne,
  $gte: Op.gte,
  $gt: Op.gt,
  $lte: Op.lte,
  $lt: Op.lt,
  $not: Op.not,
  $in: Op.in,
  $notIn: Op.notIn,
  $is: Op.is,
  $like: Op.like,
  $notLike: Op.notLike,
  $iLike: Op.iLike,
  $notILike: Op.notILike,
  $regexp: Op.regexp,
  $notRegexp: Op.notRegexp,
  $iRegexp: Op.iRegexp,
  $notIRegexp: Op.notIRegexp,
  $between: Op.between,
  $notBetween: Op.notBetween,
  $overlap: Op.overlap,
  $contains: Op.contains,
  $contained: Op.contained,
  $adjacent: Op.adjacent,
  $strictLeft: Op.strictLeft,
  $strictRight: Op.strictRight,
  $noExtendRight: Op.noExtendRight,
  $noExtendLeft: Op.noExtendLeft,
  $and: Op.and,
  $or: Op.or,
  $any: Op.any,
  $all: Op.all,
  $values: Op.values,
  $col: Op.col
};

const connection = new Sequelize(db, user, pass, { operatorsAliases });

複製代碼

limit, offset(分頁, 限制)

// 獲取10個實例/行
Project.findAll({ limit: 10 })

// 跳過8個實例/行
Project.findAll({ offset: 8 })

// 跳過5個實例,而後取5個
Project.findAll({ offset: 5, limit: 5 })
複製代碼

order(排序)

order 須要一個條目的數組來排序查詢或者一個 sequelize 方法.通常來講,你將要使用任一屬性的 tuple/array,並肯定排序的正反方向.

Subtask.findAll({
  order: [
    // 將轉義標題,並根據有效的方向參數列表驗證DESC
    ['title', 'DESC'],

    // 將按最大值排序(age)
    sequelize.fn('max', sequelize.col('age')),

    // 將按最大順序(age) DESC
    [sequelize.fn('max', sequelize.col('age')), 'DESC'],

    // 將按 otherfunction 排序(`col1`, 12, 'lalala') DESC
    [sequelize.fn('otherfunction', sequelize.col('col1'), 12, 'lalala'), 'DESC'],

    // 將使用模型名稱做爲關聯的名稱排序關聯模型的 created_at.
    [Task, 'createdAt', 'DESC'],

    // Will order through an associated model's created_at using the model names as the associations' names.
    [Task, Project, 'createdAt', 'DESC'],

    // 將使用關聯的名稱由關聯模型的created_at排序.
    ['Task', 'createdAt', 'DESC'],

    // Will order by a nested associated model's created_at using the names of the associations.
    ['Task', 'Project', 'createdAt', 'DESC'],

    // Will order by an associated model's created_at using an association object. (優選方法)
    [Subtask.associations.Task, 'createdAt', 'DESC'],

    // Will order by a nested associated model's created_at using association objects. (優選方法)
    [Subtask.associations.Task, Task.associations.Project, 'createdAt', 'DESC'],

    // Will order by an associated model's created_at using a simple association object.
    [{model: Task, as: 'Task'}, 'createdAt', 'DESC'],

    // 嵌套關聯模型的 created_at 簡單關聯對象排序
    [{model: Task, as: 'Task'}, {model: Project, as: 'Project'}, 'createdAt', 'DESC']
  ]
  
  // 將按年齡最大值降序排列
  order: sequelize.literal('max(age) DESC')

  // 按最年齡大值升序排列,當省略排序條件時默認是升序排列
  order: sequelize.fn('max', sequelize.col('age'))

  // 按升序排列是省略排序條件的默認順序
  order: sequelize.col('age')
  
  // 將根據方言隨機排序 (而不是 fn('RAND') 或 fn('RANDOM'))
  order: sequelize.random()
})
複製代碼

經常使用查詢方法

findAll

Model.findAll({
  where: {
    attr1: 42,
    attr2: 'cake'
  }
})
// WHERE attr1 = 42 AND attr2 = 'cake'


Model.findAll({
  where: {
    attr1: {
      gt: 50
      },
    attr2: {
      lte: 45
    },
    attr3: {
      in: [1,2,3]
    },
    attr4: {
      ne: 5
    }
  }
})

// WHERE attr1 > 50 AND attr2 <= 45 AND attr3 IN (1,2,3) AND attr4 != 5

Model.findAll({
  where: Sequelize.and(
    { name: 'a project' },
    Sequelize.or(
      { id: [1,2,3] },
      { id: { gt: 10 } }
   )
  )
})

// WHERE name = 'a project' AND (id` IN (1,2,3) OR id > 10)

複製代碼

findByPk

Model.findByPk(1)
複製代碼

findOne

aggregate

count

findAndCountAll

max

min

sum

create

findOrCreate

upsert

destroy

update

相關文章
相關標籤/搜索