目录

2. Model 的定义、使用与Model类的API

优质
小牛编辑
128浏览
2023-12-01

Model相当于数据库中表,有时它也会被称为“模型”或“工厂”。Model不能通过构造函数创建,而只能通过sequlize.define方法来定义或通过sequlize.import导入。通过define定义一个Model,就相当于定义了一种模型与数据表之间的映射关系,通过模型可以实现对表记录的增、删、改、查等操作。

  1. 定义描述
    • 1.1 Definition - 模型定义
    • 1.2 Data types - 数据类型
    • 1.3 Deferrable - 延时执行
    • 1.4 Getters & setters - 访问器&设置器
    • 1.5 Validations - 验证
    • 1.6 Configuration - 配置
    • 1.7 Import - 模型导入
    • 1.8 Database synchronization - 数据库同步
    • 1.9 Expansion of models - 模型扩展
  2. 模型的使用
    • 2.1 Data retrieval / Finders - 数据索引/查找
    • 2.2 Eager loading - 预加载
  3. Model类的API
    • 3.1 removeAttribute() - 移除属性
    • 3.2 sync() - 同步模型到数据库
    • 3.3 drop() - 删除数据库中的表
    • 3.4 schema() - 指定schema
    • 3.5 getTableName() - 获取表名
    • 3.6 addScope() - 添加限制范围
    • 3.7 scope() - 应用限制范围
    • 3.8 findAll() - 查询多条数据
    • 3.9 findById() - 通过Id查询单条数据
    • 3.10 findOne() - 查询单条数据
    • 3.11 aggregate() - 聚合查询
    • 3.12 count() - 统计查询结果数
    • 3.13 findAndCount() - 分页查询
    • 3.14 max() - 查询最大值
    • 3.15 min() - 查询最大值
    • 3.16 sum() - 求和
    • 3.17 build() - 创建新实例
    • 3.18 create() - 创建保存新实例
    • 3.19 findOrInitialize() - 查找或初始化
    • 3.20 findOrCreate() - 查找或创建
    • 3.21 findCreateFind() - 查找或创建
    • 3.22 upsert() - 创建或更新
    • 3.23 bulkCreate() - 创建多条记录
    • 3.24 truncate() - 截断模型
    • 3.25 destroy() - 删除记录
    • 3.26 restore() - 恢复记录
    • 3.27 update() - 更新记录
    • 3.28 describe() - 查询表信息

1. 定义描述

1.1 Definition - 模型定义

定义模型model和表之间的映射关系使用define方法。定义时Sequelize会自动为其添加createdAtupdatedAt两个属性(属性相当于表中的字段),这样你就可以知道数据什么时候插入了数据库和什么时候进行了更新。

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 后,会为列添加  NOT NULL 非空限制
 // 这意味着当执行查询(插入/更新)时相关字段为空会从数据库层抛出错误
 // 如果想在执行查询时进行值检测,请参考“验证”一节
 title: { type: Sequelize.STRING, allowNull: false},

 // 添加唯一(unique)约束后插入重复值会报错
 // unique属性可以是boolean 或 string类型
 // 如果为多个字段添加了相同的字符串那么将会是一个符合唯一键
 someUnique: {type: Sequelize.STRING, unique: true},
 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']}]}

 // 定义一个主键
 identifier: { type: Sequelize.STRING, primaryKey: true},

 // autoIncrement 选项用于创建一个自增的整型列
 incrementMe: { type: Sequelize.INTEGER, autoIncrement: true },

 // Comments 可以在MySQL 和 PG中指定定段描述
 hasComment: { type: Sequelize.INTEGER, comment: "I'm a comment!" },

 // 可以通过 "field" 属性来指定数据库中的字段名
 fieldWithUnderscores: { type: Sequelize.STRING, field: "field_with_underscores" },

 // 通过references选项可以创建外键:
 bar_id: {
   type: Sequelize.INTEGER,

   references: {
     // 引用另一个模型
     model: Bar,

     // 连接模型的列表
     key: 'id',

     // 强制使用外键约束,仅适用于 PostgreSQL
     deferrable: Sequelize.Deferrable.INITIALLY_IMMEDIATE
   }
 }
})

如果你不想在模型中使用时间戳,而只需要一些时间;或者你正在使用一个已经存在的数据库,而其中的列名与你的所需要并不一致。更多配置请参考模型配置。

1.2 Data types - 数据类型

在定义模型时,我们会指定其属性(字段)的数据类型,下面是Sequelize中支持数据类型及其与数据库中字段类型的对应关系:

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                        //   PostgreSQL 和 SQLite 中为 UUID, MySQL 中为CHAR(36) BINARY (使用 defaultValue: Sequelize.UUIDV1 或 Sequelize.UUIDV4 生成默认值)

Sequelize.RANGE(Sequelize.INTEGER)    // Defines int4range range. PostgreSQL only.
Sequelize.RANGE(Sequelize.BIGINT)     // Defined int8range range. PostgreSQL only.
Sequelize.RANGE(Sequelize.DATE)       // Defines tstzrange range. PostgreSQL only.
Sequelize.RANGE(Sequelize.DATEONLY)   // Defines daterange range. PostgreSQL only.
Sequelize.RANGE(Sequelize.DECIMAL)    // Defines numrange range. PostgreSQL only.

Sequelize.ARRAY(Sequelize.RANGE(Sequelize.DATE)) // Defines array of tstzrange ranges. PostgreSQL only.

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.

BLOB类型中你可以插入字符串或二进制buffer,在进行查询时其总是会返回buffer

如果要使用PostgreSQL的TIMESTAMP WITHOUT TIME ZONE类型,那么你需要存入一个不同的时区,并使用pg库进行转换

require('pg').types.setTypeParser(1114, function(stringValue) {
  return new Date(stringValue + "+0000");
  // e.g., UTC offset. Use any offset that you would like.
});

下面是一个额外支持的类型,如:integer, bigint, float 和 double 也同样支持 unsigned 和 zerofill。但这些属性并不能在PostgreSQL中使用:

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.define('model', {
  states: {
    type:   Sequelize.ENUM,
    values: ['active', 'pending', 'deleted']
  }
})

1.3 Deferrable - 延时执行

当你指定一个可选的外键列,那么可以在PostgreSQL定义为Deferrable类型。以下选项可用:

// Defer all foreign key constraint check to the end of a transaction
Sequelize.Deferrable.INITIALLY_DEFERRED

// Immediately check the foreign key constraints
Sequelize.Deferrable.INITIALLY_IMMEDIATE

// Don't defer the checks at all
Sequelize.Deferrable.NOT

1.4 Getters & setters - 访问器&设置器

可以在你的模型中将对象属性定义为访问/设置函数

访问器&设置器有以下两种定义方式:

  • 做为一个属性定义
  • 做为模型选项

做为一个属性定义

var Employee = sequelize.define('employee', {
  name:  {
    type     : Sequelize.STRING,
    allowNull: false,
    get      : function()  {
      var title = this.getDataValue('title');
      // 'this' allows you to access attributes of the instance
      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
  })

做为模型选项

在下面的示例中,定义了一个名为fullName的访问器,它是对this.firstnamethis.lastname两个属性引用,这个属性的一个假属性它并不是数据库中的一部分。定义假属性可以使用访问器或定义为VIRTUAL类型两种方式,Virtual类型可以验证而访问器则不能。

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(' '));
    },
  }
});

访问器&设置器内部定义的帮助函数:

检索底层属性值-总是使用this.getDataValue()

/* 访问 'title' 的属性 */
function() {
    return this.getDataValue('title');
}

设置底层属性值-总是使用this.setDataValue()

/* 设置 'title' 的属性 */
function() {
    return this.setDataValue('title', title.toString().toLowerCase());
}

1.5 Validations - 验证

模型验证,让我们可以模型的每个属性执行验证。

我们通过模型列属性的validate属性来添加验证,这些验证会在模型实例执行createupdatesave自动执行。也可以通过instance.validate()方法,来手工验证模型实例。

var ValidateMe = sequelize.define('foo', {
  foo: {
    type: Sequelize.STRING,
    validate: {
      is: ["^[a-z]+$",'i'],     // 只允许字母
      is: /^[a-z]+$/i,          // 只允许字母
      not: ["[a-z]",'i'],       // 不能使用字母
      isEmail: true,            // 检测邮箱格式 (foo@bar.com)
      isUrl: true,              // 检查Url格式 (http://foo.com)
      isIP: true,               // 检查 IPv4 或 IPv6 格式
      isIPv4: true,             // 检查 IPv4
      isIPv6: true,             // 检查 IPv6
      isAlpha: true,            // 不能使用字母
      isAlphanumeric: true,     // 只允许字母数字字符
      isNumeric: true,          // 只能使用数字
      isInt: true,              // 只能是整数
      isFloat: true,            // 只能是浮点数
      isDecimal: true,          // 检查数字
      isLowercase: true,        // 检查小写字母
      isUppercase: true,        // 检查大写字母
      notNull: true,            // 不允许null
      isNull: true,             // 只能为null
      notEmpty: true,           // 不能空字符串
      equals: 'specific value', // 只能使用指定值
      contains: 'foo',          // 必须包含子字符串
      notIn: [['foo', 'bar']],  // 不能是数组中的任意一个值
      isIn: [['foo', 'bar']],   // 只能是数组中的任意一个值
      notContains: 'bar',       // 不能包含子字符串
      len: [2, 10],              // 值的长度必在 2 和 10 之间
      isUUID: 4,                // 只能是UUID
      isDate: true,             // 只能是日期字符串
      isAfter: "2011-11-05",    // 只能使用指定日期之后的时间
      isBefore: "2011-11-05",   // 只能使用指定日期之前的时间
      max: 23,                  // 允许的最大值
      min: 23,                  // 允许的最小值
      isArray: true,            // 不能使用数组
      isCreditCard: true,       // 检查是有效的信用卡

      // 也可以自定义验证:
      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
        }
      }
    }
  }
});

验证时可以使用自定义的错误信息代替validator.js的默认信息,只需要在通过对象或数组的方式提供参数即可:

isInt: {
  msg: "Must be an integer number of pennies"
}

或者参数中同样需要提供args属性:

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

模型验证

Validations同可以用于模型的检测,只需要在字段定义之后定义验证即可。如,在经纬度的应用的我们会需要latitudelongitude都不为空或都为空,这时我们可以像下面这样验证:

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 }
  },
}, {
  validate: {
    bothCoordsOrNone: function() {
      if ((this.latitude === null) !== (this.longitude === null)) {
        throw new Error('Require either both latitude and longitude or neither')
      }
    }
  }
})

1.6 Configuration - 配置

定义模型时,可以通过配置来设置列名等相关信息:

var Bar = sequelize.define('bar', { /* bla */ }, {
  // 不要添加时间戳属性 (updatedAt, createdAt)
  timestamps: false,

  // 不从数据库中删除数据,而只是增加一个 deletedAt 标识当前时间
  // paranoid 属性只在启用 timestamps 时适用
  paranoid: true,

  // 不使用驼峰式命令规则,这样会在使用下划线分隔
  // 这样 updatedAt 的字段名会是 updated_at
  underscored: true,

  // 禁止修改表名. 默认情况下
  // sequelize会自动使用传入的模型名(define的第一个参数)做为表名
  // 如果你不想使用这种方式你需要进行以下设置
  freezeTableName: true,

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

如果你想sequelize处理时间戳,但只在个别情况下使用,那么你可以对使用的列单独重载:

var Foo = sequelize.define('foo',  { /* bla */ }, {
  // 不要忘了启用 timestamps
  timestamps: true,

  // 不想使用 createdAt
  createdAt: false,

  // 想 updatedAt 的实际名为 'updateTimestamp'
  updatedAt: 'updateTimestamp'

  // 要将 deletedAt 设置为 destroyTime (注意要启用paranoid)
  deletedAt: 'destroyTime',
  paranoid: true
})

配置时,也可以修改数据库引擎。如,将默认的InnoDB修改为MyISAM:

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

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

或者指定一个表描述(MySql和PG中):

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

注意:字段attributes同样可以添加comment属性,但出于兼容性考虑自sequelize V1.7+起已不再将此属性同步到数据库中,但为字段添加这个属性依然是增加可读性的不错的方式。

1.7 Import - 模型导入

我们可以将模型定义为一个单独的文件,并通过导入。通过文件导入返回的对象与通过defined方法定义的模型完全一致,两者都是instance模型实例。自v1.5.0起,sequlize会对导入进行缓存,这样就不用担心多次对文件修改造成的一些问题。

如,我们在project.js文件中定义一个名为project的模型:

// 这个文件定义于 /path/to/models/project.js
module.exports = function(sequelize, DataTypes) {
  return sequelize.define("project", {
    name: DataTypes.STRING,
    description: DataTypes.TEXT
  })
}

我们可以app.js或其它需要的地方引入定义的模型:

var Project = sequelize.import(__dirname + "/path/to/models/project")

import同样可以使用回调函数参数的使用方式:

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

1.8 Database synchronization - 数据库同步

开始一个新项目时,我们并没有数据库结构,使用Sequelize时,并不需要先定义好数据库结构。我们只要定义好模型,然后进行同步即可。

Sequelize支持创建表和删除表:

// 通过 sync 方法同步数据结构
// 即,创建表
Project.sync()
Task.sync()

// 强制创建
// 通过设置 force 属性会首先删除表并重新创建
Project.sync({force: true})

// 删除表
Project.drop()
Task.drop()

// 事件处理
Project.[sync|drop]().then(function() {
  // 处理成功
}).catch(function(error) {
  // 出了点问题^~^
})

.sync({ force: true })会删除并重建表,这时我们可以添加match选项,只重建正则表达式匹配的表:

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

1.9 Expansion of models - 模型扩展

开始一个新项目时,我们并没有数据库结构,使用Sequelize时,并不需要先定义好数据库结构。我们只要定义好模型,然后进行同步即可。

自定义方法

Sequelize允许我们为实例添加自定义方法,可以像下面这样定义:

var Foo = sequelize.define('foo', { /* attributes */}, {
  classMethods: {
    method1: function(){ return 'smth' }
  },
  instanceMethods: {
    method2: function() { return 'foo' }
  }
})

// Example:
Foo.method1()
Foo.build().method2()

虚拟访问器

也可以设置虚拟访问器:

var User = sequelize.define('user', { firstname: Sequelize.STRING, lastname: Sequelize.STRING }, {
  instanceMethods: {
    getFullname: function() {
      return [this.firstname, this.lastname].join(' ')
    }
  }
})

// Example:
User.build({ firstname: 'foo', lastname: 'bar' }).getFullname() // 'foo bar'

全局方法

还可以定义用于所有模型实例的全局方法:

var sequelize = new Sequelize('database', 'username', 'password', {
  // Other options during the initialization could be here
  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后创建。下面是几种添加索引的方式:

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}]
    }
  ]
})

2. 模型的使用

2.1 Data retrieval / Finders - 数据索引/查找

查找方法是为了从数据库中查询数据,这些方法不是返回原始数据对象,而是返回模型实例。因会其返回的是模型实例,所以在文档的查询结果中可以任意调用模型实例的成员、方法等。(更多实例介绍请参考:instance

下面是一些常用的查询方法。

find - 从数据库中查找一个指定元素

// 按已知 id查找
Project.findById(123).then(function(project) {
  // project 是一个 Project 实例,且包含存储在数据中的数据
  // 当不存在 id 为123的记录时 project 为 null
})

// 按属性查找
Project.findOne({ where: {title: 'aProject'} }).then(function(project) {
  // project 是匹配到的第一个 title 为 'aProject' 的 Projects 或 null
})


Project.findOne({
  where: {title: 'aProject'},
  attributes: ['id', ['name', 'title']]
}).then(function(project) {
  // project 是匹配到的第一个 title 为 'aProject' 的 Projects 或 null
  // project 的 project.title 属性中会包含 'name'
})

findOrCreate - 从数据库中查找一个指定元素如果不存在则创建记录

findOrCreate可用于检测一个不确定是否存在的元素,如果存在则返回记录,不存在时会使用提供的默认值新建记录。

如,当数据不存在时,其执行效果如下:

User
  .findOrCreate({where: {username: 'itbilu.com'}, defaults: {job: 'Technical Lead JavaScript'}})
  .spread(function(user, created) {
    console.log(user.get({
      plain: true
    }))
    console.log(created)

    /*
      {
        username: 'itbilu.com',
        job: 'Technical Lead JavaScript',
        id: 1,
        createdAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET),
        updatedAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET)
      }
      created: true
    */
  })

当数据存在时,会返回记录:

User
  .create({ username: 'fnord', job: 'omnomnom' })
  .then(function() {
    User
      .findOrCreate({where: {username: 'fnord'}, defaults: {job: 'something else'}})
      .spread(function(user, created) {
        console.log(user.get({
          plain: true
        }))
        console.log(created)

        /*
          {
            username: 'fnord',
            job: 'omnomnom',
            id: 2,
            createdAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET),
            updatedAt: Fri Mar 22 2013 21: 28: 34 GMT + 0100(CET)
          }
          created: false
        */
      })
  })

findAndCountAll - 从数据库中查找多个元素,返回数据与记录总数

这个方法是findAllcount两个方法的便捷形式,这在你想使用limitoffset进行分页查询时非常有用。

在返回值中,会包含以下两个属性:

  • count - 整数,匹配到的总记录数
  • rows - 对象数据,通过 limit 和 offset匹配的当前页数据
Project
  .findAndCountAll({
     where: {
        title: {
          $like: 'foo%'
        }
     },
     offset: 10,
     limit: 2
  })
  .then(function(result) {
    console.log(result.count);
    console.log(result.rows);
  });

findAndCountAll同样支持使用include包含,使用包含时只有将required设置为true才会添加到count部分:

User.findAndCountAll({
  include: [
     { model: Profile, required: true}
  ],
  limit: 3
});

使用include时,两个模型之间应该存在主/外键关系,如果不存在就应该在include中手工建立连接。

在上面的示例中,为Profile设置了required,所以在查询时会使用INNER JOIN内连接。

findAll - 从数据库中查找多个元素

findAndCountAll中使用的查询选项同样适用于findAll方法。

// 查询多条记录
Project.findAll().then(function(projects) {
  // projects 是一个包含Project实例的数组
})

// 同样的,all是findAll的别名方法:
Project.all().then(function(projects) {
  // projects 是一个包含Project实例的数组
})

// 通过指定属性查找
Project.findAll({ where: { name: 'A Project' } }).then(function(projects) {
// projects 是一个包含 Project 实例的数组
})

// 查询时使用字符串替换
Project.findAll({ where: ["id > ?", 25] }).then(function(projects) {
  // projects 是一个包含 Project 实例的数组,各实例的id 大于25
})

// 查询指定范围
Project.findAll({ where: { id: [1,2,3] } }).then(function(projects) {
  // projects 是一个包含 Project 实例的数组,各实例id 是1, 2, 或 3
  // 这在实例执行时,会使用 IN查询
})

Project.findAll({
  where: {
    id: {
      $and: {a: 5}           // AND (a = 5)
      $or: [{a: 5}, {a: 6}]  // (a = 5 OR a = 6)
      $gt: 6,                // id > 6
      $gte: 6,               // id >= 6
      $lt: 10,               // id < 10
      $lte: 10,              // id  [1, 2] (PG array contains operator)
      $contained: [1, 2]     // <@ [1, 2] (PG array contained by operator)
      $any: [2,3]            // ANY ARRAY[2, 3]::INTEGER (PG only)
    },
    status: {
      $not: false,           // status NOT FALSE
    }
  }
})

IN/OR 等复合筛选

如果要在查询中使用ANDORDOT等筛选条件,可以查询的where中指定$and$or$not等属性:

Project.findOne({
  where: {
    name: 'a project',
    $or: [
      { id: [1,2,3] },
      { id: { $gt: 10 } }
    ]
  }
})

Project.findOne({
  where: {
    name: 'a project',
    id: {
      $or: [
        [1,2,3],
        { $gt: 10 }
      ]
    }
  }
})

这个查询生成的实际SQL语句为:

SELECT *
FROM `Projects`
WHERE (
  `Projects`.`name` = 'a project'
   AND (`Projects`.`id` IN (1,2,3) OR `Projects`.`id` > 10)
)
LIMIT 1;

$not示例:

Project.findOne({
  where: {
    name: 'a project',
    $not: [
      { id: [1,2,3] },
      { array: { $contains: [3,4,5] } }
    ]
  }
});

将生成以下语句:

SELECT *
FROM `Projects`
WHERE (
  `Projects`.`name` = 'a project'
   AND NOT (`Projects`.`id` IN (1,2,3) OR `Projects`.`array` @> ARRAY[1,2,3]::INTEGER[])
)
LIMIT 1;

对数据集使用limitoffsetordergroup

// 使用 limit 限制返回结果数
Project.findAll({ limit: 10 })

// 跳过前 10 条结果
Project.findAll({ offset: 10 })

// 跳过前 10 条结果后,返回两条数据
Project.findAll({ offset: 10, limit: 2 })

分组与排序的语法是相似的,如下:

Project.findAll({order: 'title DESC'})
// ORDER BY title DESC

Project.findAll({group: 'name'})
// GROUP BY name

传入简单的字符串时,查询字符串会逐字查询,即列名不转义。如果需要列名转义,可以提供一个数组参数。

something.findOne({
  order: [
    'name',
    // will return `name`
    'username DESC',
    // will return `username DESC` -- i.e. don't do it!
    ['username', 'DESC'],
    // will return `username` DESC
    sequelize.fn('max', sequelize.col('age')),
    // will return max(`age`)
    [sequelize.fn('max', sequelize.col('age')), 'DESC'],
    // will return max(`age`) DESC
    [sequelize.fn('otherfunction', sequelize.col('col1'), 12, 'lalala'), 'DESC'],
    // will return otherfunction(`col1`, 12, 'lalala') DESC
    [sequelize.fn('otherfunction', sequelize.fn('awesomefunction', sequelize.col('col'))), 'DESC']
    // will return otherfunction(awesomefunction(`col`)) DESC, This nesting is potentially infinite!
    [{ raw: 'otherfunction(awesomefunction(`col`))' }, 'DESC']
    // This won't be quoted, but direction will be added
  ]
})

更多关于聚合查询,请参考:在Sequelize中使用group by分组聚合查询

原始查询

默情况下,Sequlize人为查询结构创建实例,通过这个实例可以进行数据的更新、删除等操作。有时候我只需要显示数据集,而不需要进行处理,这时可以通过设置raw选项来返回原始数据:

// 增加 raw 选项后,会返回数据库中的原始结果
Project.findAll({ where: { ... }, raw: true })

count - 统计数据库中的元素数

count可以统计数据库中的元素数:

Project.count().then(function(c) {
  console.log("There are " + c + " projects!")
})

Project.count({ where: ["id > ?", 25] }).then(function(c) {
  console.log("There are " + c + " projects with an id greater than 25.")
})

max - 查找指定表中最大值

// 数据库中有3条记录,年龄分别是 10, 5, 40
Project.max('age').then(function(max) {
  // 会返回 40
})

Project.max('age', { where: { age: { lt: 20 } } }).then(function(max) {
  // 会返回 10
})

min - 查找指定表中最小值

// 数据库中有3条记录,年龄分别是 10, 5, 40
Project.min('age').then(function(min) {
  // 会返回 5
})

Project.min('age', { where: { age: { $gt: 5 } } }).then(function(min) {
  // 会返回 10
})

sum - 对指定属性求和

// 数据库中有3条记录,年龄分别是 10, 5, 40
Project.sum('age').then(function(sum) {
  // 会返回 55
})

Project.sum('age', { where: { age: { $gt: 5 } } }).then(function(sum) {
  // 会返回 50
})

2.2 Eager loading - 预加载

从数据库中加载数据时,除数据本身外还想得到与之相关联的数据-这就是所谓的预加载。也就是说,使用findfindAll查询数据时,通过include属性同时加载关联的数据。

假设有以下数据结构:

var User = sequelize.define('user', { name: Sequelize.STRING })
  , Task = sequelize.define('task', { name: Sequelize.STRING })
  , Tool = sequelize.define('tool', { name: Sequelize.STRING })

Task.belongsTo(User)
User.hasMany(Task)
User.hasMany(Tool, { as: 'Instruments' })

sequelize.sync().then(function() {
  // this is where we continue ...
})

通过belongsTohasMany建立关系后,就可以像下面这样查询:

Task.findAll({ include: [ User ] }).then(function(tasks) {
  console.log(JSON.stringify(tasks))

  /*
    [{
      "name": "A Task",
      "id": 1,
      "createdAt": "2013-03-20T20:31:40.000Z",
      "updatedAt": "2013-03-20T20:31:40.000Z",
      "userId": 1,
      "user": {
        "name": "John Doe",
        "id": 1,
        "createdAt": "2013-03-20T20:31:45.000Z",
        "updatedAt": "2013-03-20T20:31:45.000Z"
      }
    }]
  */
})

由于TaskUser1对多的关系,所在以查询时user会做为一个对象属性被同时加载。

下面我们进行一个多对多的查询:

User.findAll({ include: [ Task ] }).then(function(users) {
  console.log(JSON.stringify(users))

  /*
    [{
      "name": "John Doe",
      "id": 1,
      "createdAt": "2013-03-20T20:31:45.000Z",
      "updatedAt": "2013-03-20T20:31:45.000Z",
      "tasks": [{
        "name": "A Task",
        "id": 1,
        "createdAt": "2013-03-20T20:31:40.000Z",
        "updatedAt": "2013-03-20T20:31:40.000Z",
        "userId": 1
      }]
    }]
  */
})

多对多的关系中,相关数据会做为一个数组属性被同时加载。

关联查询时,可以使用as选项为关系数据指定别名:

User.findAll({ include: [{ model: Tool, as: 'Instruments' }] }).then(function(users) {
  console.log(JSON.stringify(users))

  /*
    [{
      "name": "John Doe",
      "id": 1,
      "createdAt": "2013-03-20T20:31:45.000Z",
      "updatedAt": "2013-03-20T20:31:45.000Z",
      "Instruments": [{
        "name": "Toothpick",
        "id": 1,
        "createdAt": null,
        "updatedAt": null,
        "userId": 1
      }]
    }]
  */
})

关联查询时,同样可以使用where选项对关联数据进行筛选:

User.findAll({
    include: [{
        model: Tool,
        as: 'Instruments',
        where: { name: { $like: '%ooth%' } }
    }]
}).then(function(users) {
    console.log(JSON.stringify(users))

    /*
      [{
        "name": "John Doe",
        "id": 1,
        "createdAt": "2013-03-20T20:31:45.000Z",
        "updatedAt": "2013-03-20T20:31:45.000Z",
        "Instruments": [{
          "name": "Toothpick",
          "id": 1,
          "createdAt": null,
          "updatedAt": null,
          "userId": 1
        }]
      }],

      [{
        "name": "John Smith",
        "id": 2,
        "createdAt": "2013-03-20T20:31:45.000Z",
        "updatedAt": "2013-03-20T20:31:45.000Z",
        "Instruments": [{
          "name": "Toothpick",
          "id": 1,
          "createdAt": null,
          "updatedAt": null,
          "userId": 1
        }]
      }],
    */
  })

注意:使用include.where条件时,include.requied会被隐式的设置为true,即在查询时会使用INNER JOIN内连接。

全关联

如果多个模型间存在关联关系,而我们在查询时又要查询所有的数据,就可以设置all: true来关联所有模型:

User.findAll({ include: [{ all: true }]});

包括软删除的数据

如果要在结果中包含软删除的数据,请将include.paranoid设置为true

User.findAll({
    include: [{
        model: Tool,
        where: { name: { $like: '%ooth%' } },
        paranoid: true // 查询并加载软删除的数据
    }]
});

预加载关联数据的排序

1对多(one-to-many)的关系中:

Company.findAll({ include: [ Division ], order: [ [ Division, 'name' ] ] });
Company.findAll({ include: [ Division ], order: [ [ Division, 'name', 'DESC' ] ] });
Company.findAll({
  include: [ { model: Division, as: 'Div' } ],
  order: [ [ { model: Division, as: 'Div' }, 'name' ] ]
});
Company.findAll({
  include: [ { model: Division, as: 'Div' } ],
  order: [ [ { model: Division, as: 'Div' }, 'name', 'DESC' ] ]
});
Company.findAll({
  include: [ { model: Division, include: [ Department ] } ],
  order: [ [ Division, Department, 'name' ] ]
});

多对多(many-to-many)的关系中同样可以使用排序:

Company.findAll({
  include: [ { model: Division, include: [ Department ] } ],
  order: [ [ Division, DepartmentDivision, 'name' ] ]
});

嵌套预加载

可以在关联模型中嵌套预加载关系模型:

User.findAll({
  include: [
    {model: Tool, as: 'Instruments', include: [
      {model: Teacher, include: [ /* etc */]}
    ]}
  ]
}).then(function(users) {
  console.log(JSON.stringify(users))

  /*
    [{
      "name": "John Doe",
      "id": 1,
      "createdAt": "2013-03-20T20:31:45.000Z",
      "updatedAt": "2013-03-20T20:31:45.000Z",
      "Instruments": [{ // 1:M and N:M association
        "name": "Toothpick",
        "id": 1,
        "createdAt": null,
        "updatedAt": null,
        "userId": 1,
        "Teacher": { // 1:1 association
          "name": "Jimi Hendrix"
        }
      }]
    }]
  */
})

这会生成一个外连接,但where子句的关系模型会使用内连接并返回唯一一个子句:

User.findAll({
  include: [{
    model: Tool,
    as: 'Instruments',
    include: [{
      model: Teacher,
      where: {
        school: "Woodstock Music School"
      },
      required: false
    }]
  }]
}).then(function(users) {
  /* ... */
})

include同样支持嵌套加载:

User.findAll({ include: [{ all: true, nested: true }]});

3. Model类的API

Model相当于数据库中表,有时你也会看到它被称为“模型”、或简单的被为“工厂”。这个类不能显式的(通过构造函数)创建实例,而是应该通过sequelize.define方法来创建,对于已经创建可以通过sequelize.import方法来导入。

3.1 removeAttribute() - 移除属性

removeAttribute([attribute])

从已定义的模型中移除属性

参数

名称类型说明
[attribute]String

使用示例:

let User = sequelize.define('user', {
  firstName: Sequelize.STRING,
  lastName: Sequelize.STRING
});

User.sync().then(function(result){
  User.create({firstName:'xxxx', lastName:'xxxx'})
  .then(function(result){
    User.findOne({raw:true})
    .then(function(result){
      console.log(result); // { id: 1, firstName: 'xxxx', lastName: 'xxxx'}

      // 移'firstName'属性
      User.removeAttribute('firstName');
      User.findOne({raw:true})
      .then(function(result){
        console.log(result);  // // { id: 1, lastName: 'xxxx'}
      })
    })  
  })
})

3.2 sync() - 同步模型到数据库

sync() -> Promise.

同步Model结构到数据库中,即:在数据库中创建表。执行成功后,会在回调中返回模弄的实例(this)。

sequelize.sync的不同

Model.sync()只会同步当前模型到数据库中,而sequelize.sync()会同步sequelize实例中定义所有模型。

let User = sequelize.define('user', {
  firstName: Sequelize.STRING,
  lastName: Sequelize.STRING
});

let Role = sequelize.define('role', {
  roleName: Sequelize.STRING
});

let UserRole = sequelize.define('userRole', {
  userId: Sequelize.INTEGER,
  roleId: Sequelize.STRING
});

User.sync().then(function(result){
    // 同步了'User'一个模型
})

sequelize.sync().then(function(result){
  // 同步了'Role'、'UserRole'、'UserRole'三个模型
})

相关

  • Sequelize#sync

3.3 drop() - 删除数据库中的表

drop([options]) -> Promise

删除Model在数据库中对应的表。

参数

名称类型属性
[options]Object
[options.cascade=false]Boolean同时移除依赖于该表的对象,如视图。仅 postgres适用
[options.logging=false]Function一个函数用于打印查询时的sql
[options.benchmark=false]Boolean在打印日志时同时输出执行SQL花费的时候(毫秒)

3.4 schema() - 指定schema

schema(schema, [options]) -> this

Model指定schema(数据库)。在postgres中将会设置为"schema"."tableName",而在mysql和sqlite中将会设置为'schema.tablename'

参数

名称类型属性
schemaStringschema名
[options]Object
[options.schemaDelimiter='.']Stringschema与表名的分隔符
[options.logging=false]Function一个函数用于打印查询时的sql
[options.benchmark=false]Boolean在打印日志时同时输出执行SQL花费的时候(毫秒)

3.5 getTableName() - 获取表名

getTableName([options]) -> String|Object

获取Model在数据库中的表名。在未指定schema时会返回模型名,或返回一个包含tableNameschemadelimiter属性的对象。

参数

名称类型属性
schemaStringschema名
[options]Object
[options.logging=false]Function一个函数用于打印查询时的sql
[options.benchmark=false]Boolean在打印日志时同时输出执行SQL花费的时候(毫秒)

3.6 addScope() - 添加限制范围

addScope(name, scope, [options])

为模型添加一个新的限制范围。在定义模型时如果未指定验证,这一方法会非常有用。

如果指定的限制已经存在,默认会抛出异常,这时可以传入override: true选项来解决。

参数

名称类型说明
nameString限制范围名。使用defaultScope是,会替换默认的限制
scopeObject | Function
[options]Object
[options.override=false]Boolean

3.7 scope() - 应用限制范围

scope(options*) -> Model

在应用在define定义模型时创建的作用范围。如,在定义模型时我们会像下面这样创建作用范围:

var Model = sequelize.define('model', attributes, {
  defaultScope: {
    where: {
      username: 'dan'
    },
    limit: 12
  },
  scopes: {
    isALie: {
      where: {
        stuff: 'cake'
      }
    },
    complexFunction: function(email, accessLevel) {
      return {
        where: {
          email: {
            $like: email
          },
          accesss_level {
            $gte: accessLevel
          }
        }
      }
    }
  }
})

定义默认的限制范围后,默认限制会在每次查询时起作用:

Model.findAll() // WHERE username = 'dan'
Model.findAll({ where: { age: { gt: 12 } } }) // WHERE age > 12 AND username = 'dan'

我们可以通过scope()像下面这样应用限制范围:

Model.scope({ method: ['complexFunction' 'dan@sequelize.com', 42]}).findAll()
// WHERE email like 'dan@sequelize.com%' AND access_level >= 42

3.8 findAll() - 查询多条数据

findAll([options]) -> Promise.<Array.<Instance>>

查询多个实例(多条数据)。

如,在查询中使用AND=

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

在查询中使用OR

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

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

查询成功后会返回包含多个实例(instance)的数组。

别名:all

相关

  • Sequelize#query

参数

名称类型说明
[options]Object
[options.where]Object一个描述查询限制范围(WHERE条件)的对象
[options.attributes]Array.<String> | Object要查询的属性(字段)列表,或一个includeexclude 对象的键。
要对属性进行重命名,可以传入一个包含两个元素的数组-第一个表示属性在数据库中的名称或(或一些类似Sequelize.literal, Sequelize.fn等的表达式),第二个属性表示要在返回实例中使用的名称
[options.attributes.include]Array.<String>选择所有模型属性并添加一些附加值,用于聚合计算。如:
{attributes:{
include:[[sequelize.fn('COUNT', sequelize.col('id')),'total']]}
[options.attributes.exclude]Array.<String>选择模型中除少数属性外的所有属性,这主要出于安全目录。 如:
{ attributes: { exclude: ['password'] } }
[options.paranoid=true]Booleantrue时,只会未删除的记录会返回,否则会返回删除和未删除的全部记录
[options.include]Array.<Object | Model>一个用于左连接的连接列表,
支持{ include: [ Model1, Model2, ...]}{ include: [{ model: Model1, as: 'Alias' }]}的形式
如果你的连接要设置as (如 X.hasMany(Y, { as: 'Z }, 你需要将要加载的 Y 的as属性指定为Z)
[options.include[].model]Model你想要加载的模型
[options.include[].as]String别名关系,如果你想对要加载的模型起别名。
对于 hasOne / belongsTo, 这地应该使用单数形式名,而对于hasMany则应该使用复数形式名
[options.include[]
.association]
Association想要加载的关系(这可以用来替代提供的一个model/as对)
[options.include[].where]Object用于子模型的WHERE分句。注意,这会对要加载的使用内连接,除非显示指定required: false
[options.include[].or=false]Boolean是否将 ON 和 WHERE 分名与 OR绑定在一起而不是替换 AND
[options.include[].on]Object为连接提供你的 ON 条件
[options.include[].attributes]Array.<String>要从子模型中查询的属性列表
[options.include[].required]Boolean如果为true,会转换为内连接。这意味着,只有匹配到子模型的父模型才会被加载。include.where设置后为True,其它情况 false
[options.include[].separate]Boolean如果为true,运行一个单独的查询来获取关联的实例,仅支持hasMany关系
[options.include[].limit]Number限制连接的行数,仅在include.separate=true时支持
[options.include[]
.through.where]
Object为 belongsToMany 关系,过滤连接的模型
[options.include[]
.through.attributes]
Array在 belongsToMany 关系中,连接模型选择的属性列表
[options.include[].include]Array.<Object | Model>进一步嵌套相关模型
[options.order]String | Array | Sequelize.fn指定一个排序. 如果是字符串,那么会进行编码。
如果是数组,那么可以依次提供多组列名/排序函数,每一组包含两个元素,第一个是排序字段名,第二个是排序方式,如: order: [['name', 'DESC']]。这种情况下,列名会进行编码而排序方向不会
[options.limit]Number
[options.offset]Number
[options.transaction]Transaction在事务中执行查询
[options.lock]String | Object锁定已选行. 可选项有: transaction.LOCK.UPDATE、 transaction.LOCK.SHARE,
Postgres还支持: supports transaction.LOCK.KEY_SHARE、 transaction.LOCK.NO_KEY_UPDATE 和指定模型的连接锁
详见 transaction.LOCK
[options.raw]Boolean返回原始结果. 详见 sequelize.query
[options.logging=false]Function一个用于打印执行SQL语句的函数
[options.having]Object
[options
.searchPath=DEFAULT]
String一个用于指定 schema 的 search_path 的可选项(仅 Postgres 适用)
[options.benchmark=false]Boolean打印执行SQL语句时,同时输出执行时间(毫秒)

3.9 findById() - 通过Id查询单条数据

findById(id, [options]) -> Promise.<Instance>

通过Id(主键)查询单个实例(单条数据)。

参数

名称类型说明
idNumber | String | Buffer要查询实例的主键
[options]Object
[options.transaction]Transaction在事务中执行查询
[options
.searchPath=DEFAULT]
String指定schema的 search_path (仅 Postgres)

别名:findByPrimary

3.10 findOne() - 查询单条数据

findOne(options]) -> Promise.<Instance>

查询单个实例(单条数据)。这将会使用LIMIT 1查询条件,所以回调中总是返回单个实例。

参数

名称类型说明
[options]Object
[options.transaction]Transaction在事务中执行查询
[options.searchPath=DEFAULT]String指定schema的 search_path (仅 Postgres)

3.11 aggregate() - 聚合查询

aggregate(field, aggregateFunction, [options]) -> Promise.<options.dataType|object>

在指定字段field上运行聚合查询。

参数

名称类型说明
fieldString要运行聚合的字段。可以是字段名或*
aggregateFunctionString聚合函数,如sum, maxetc.
[options]Object查询选项,可通过sequelize.query查看所有选项
[options.where]Object查询属性
[options.logging=false]Function一个用于打印查询时所执行sql的函数
[options.dataType]DataType | String结果类型。如field是模型中的字段,默认为字段的类型,其它情况为默认为 float
[options.distinct]boolean为字段使用DISTINCT聚合查询
[options.transaction]Transaction在事务中运行查询
[options.plain]Boolean当为true时,第一个aggregateFunction的返回值为dataType指定和返回,如果添加了额外的属性,则由group分句决定。设置plainfalse 时会返回所有返回行中的所有值 。默认为 true
[options.benchmark=false]Boolean当打印SQL日志时同时输出查询执行时间(毫秒)

3.12 count() - 统计查询结果数

count([options]) -> Promise.<Integer>

统计符合查询条件的结果总数。

如果提供了include,将计算匹配关联的数目

参数

名称类型说明
[options]Object
[options.where]Object查询属性(条件)
[options.include]ObjectInclude 选项
[options.distinct]boolean在主键上使用 COUNT(DISTINCT(col)), Model.aggregate 要使用其它列
[options.attributes]Objectgroup中联合使用
[options.group]Object创建复杂统计时,会返回所需要的多行
[options.transaction]Transaction在事务中执行查询Transaction to run query under
[options.logging=false]Function一个用于打印查询时所执行sql的函数
[options
.searchPath=DEFAULT]
String指定schema的 search_path (仅 Postgres)
[options.benchmark=false]Boolean当打印SQL日志时同时输出查询执行时间(毫秒)

3.13 findAndCount() - 分页查询

findAndCount([findOptions]) -> Promise.<Object>

查询由offset/limit指定的所有匹配行,并返回查询条件所匹配的总数量。

Model.findAndCountAll({
  where: ...,
  limit: 12,
  offset: 12
}).then(function (result) {
  ...
})

在上面查询中,result是一个包含以两个属性的对象:

{
  rows: [],
  count: 
}

result.rows是匹配的查询行,result.count是查询条件匹配的总数量。

如果提供了include,将计算匹配关联的数目

User.findAndCountAll({
  include: [
     { model: Profile, required: true}
  ],
  limit 3
});

参数

名称类型说明
[findOptions]Object参见 findAll

别名:findAndCountAll

3.14 max() - 查询最大值

max(field, [options]) -> Promise.<Any>

查询指定字段的最大值

参数

名称类型说明
fieldString
[options]Object参见 Object

3.15 min() - 查询最大值

min(field, [options]) -> Promise.

查询指定字段的最小值

参数

名称类型说明
fieldString
[options]Object参见 Object

3.16 sum() - 求和

sum(field, [options]) -> Promise.<Number>

对指定字段求和

参数

名称类型说明
fieldString
[options]Object参见 Object

3.17 build() - 创建新实例

build(values, [options]) -> Instance

创建一个新的模型实例,Values参数为新例指定的键值对对象

参数

名称类型说明
valuesObject
[options]Object
[options.raw=false]Boolean设置为true时,值会忽略字段和虚拟设置器
[options.isNewRecord=true]Boolean
[options.include]Array用于构建prefetched/included模型,参见 set

3.18 create() - 创建保存新实例

create(values, [options]) -> Promise.<Instance>

构建一个新的模型实例,并进行保存。与build()方法不同的是,此方法除创建新实例外,还会将其保存到对应数据库表中。

参数

名称类型说明
valuesObject
[options]Object
[options.raw=false]Boolean设置为true时,值会忽略字段和虚拟设置器
[options.isNewRecord=true]Boolean
[options.fields]Array如果设置后,只有列表中区别的列才会进行保存
[options.include]Array用于构建prefetched/included模型,参见 set
[options.onDuplicate]String
[options.transaction]Transaction在事务中执行查询
[options.logging=false]Function一个用于打印查询时所执行sql的函数
[options.searchPath=DEFAULT]String指定schema的 search_path (仅 Postgres)
[options.benchmark=false]Boolean当打印SQL日志时同时输出查询执行时间(毫秒)

3.19 findOrInitialize() - 查找或初始化

findOrInitialize -> Promise.<Instance, initialized>

查找一行记录,如果不存在则创建(不保存)实例

参数

名称类型说明
optionsObject
options.whereObject查询属性
[options.defaults]Object用于创建新实例的默认值
[options.transaction]Transaction在事务中执行查询
[options.logging=false]Function一个用于打印查询时所执行sql的函数
[options.searchPath=DEFAULT]String指定schema的 search_path (仅 Postgres)
[options.benchmark=false]Boolean当打印SQL日志时同时输出查询执行时间(毫秒)

别名:findOrBuild

3.20 findOrCreate() - 查找或创建

findOrCreate(options) -> Promise.<Instance, created>

查找一行记录,如果不存在则创建实例并保存到数据库中

在这个方法中,如果options对象中没有传入事务,那么会在内部自动创建一个新的事务,以防止在创建完成之前有新匹配查询进入。

参数

名称类型说明
optionsObject
options.whereObject查询属性
[options.defaults]Object用于创建新实例的默认值
[options.transaction]Transaction在事务中执行查询

3.21 findCreateFind() - 查找或创建

findCreateFind(options) -> Promise.<Instance, created>

效率更高的findOrCreate,不会在事务中执行。首先会尝试进行查询,如果为空则尝试创建,如果是唯一约束则尝试再次查找。

参数

名称类型说明
optionsObject
options.whereObject查询属性
[options.defaults]Object用于创建新实例的默认值
[options.transaction]Transaction在事务中执行查询

3.22 upsert() - 创建或更新

upsert(values, [options]) -> Promise.<created>

创建或更新一行。如果匹配到主键或唯一约束键时会进行更新。

执行详细:

  • MySQL - 做为单条查询执行 INSERT values ON DUPLICATE KEY UPDATE values
  • PostgreSQL - 作为一个临时性的异常处理函数来实现: INSERT EXCEPTION WHEN unique_constraint UPDATE
  • SQLite - 做为两条查询执行 INSERT; UPDATE。这意味着,无论该行是否存在都会进行更新

参数

名称类型说明
valuesObject
[options]Object
[options.validate=true]Boolean插入前进行验证
[options.fields=Object.keys(this.attributes)]Array要插入/更新字段。默认全部
[options.transaction]Transaction在事务中执行查询

别名:insertOrUpdate

3.23 bulkCreate() - 创建多条记录

bulkCreate(records, [options]) -> Promise.<Array.<Instance>>

批量创建并保存多个实例。

处理成功后,会在回调函数中返回一个包含多个实例的数组。

参数

名称类型说明
recordsArray要创建实例的对象(键/值 对)列表
[options]Object
[options.fields]Array要插入的字段。默认全部
[options.validate=true]Boolean插入每条记录前进行验证
[options.hooks=true]Boolean在执行前/后创建钩子
[options.individualHooks=false]Boolean在执行前/后为每个实例创建钩子
[options.ignoreDuplicates=false]Boolean忽略重复主键(Postgres不支持)
[options.updateOnDuplicate]Array如果行键已存在是否更新(mysql & mariadb支持). 默认为更新
[options.transaction]Transaction在事务中执行查询

3.24 truncate() - 截断模型

truncate([options]) -> Promise

截断模型的所有实例,这个方法是Model.destroy({ truncate: true })便捷方法。

参数

名称类型说明
recordsArray要创建实例的对象(键/值 对)列表
[options]Object
[options.transaction]Transaction在事务中执行查询
[options.cascade=false]Boolean | function仅适用于连接查询时的TRUNCATE操作,截断所有外键匹配的表

3.25 destroy() - 删除记录

destroy(options) -> Promise.<Integer>

删除多个实例,或设置deletedAt的时间戳为当前时间(当启用paranoid时)

执行成功后返回被删除的行数

参数

名称类型说明
optionsObject
[options.where]Object筛选条件
[options.hooks=true]Boolean在执行前/后创建钩子
[options.individualHooks=false]Boolean在执行前/后为每个实例创建钩子
[options.limit]Number要删除的行数
[options.force=false]Boolean删除而不是设置 deletedAt 为当前时间戳 (仅启用 paranoid 时适用)
[options.truncate=false]Boolean设置为true时,会使用TRUNCATE代替DELETE FROM,这时会忽略wherelimit选项
[options.cascade=false]Boolean仅适用于连接查询时的TRUNCATE操作,截断所有外键匹配的表
[options.transaction]Transaction在事务中执行查询

3.26 restore() - 恢复记录

restore(options) -> Promise.<undefined>

恢复多个实例,当启用paranoid

参数

名称类型说明
optionsObject
[options.where]Object筛选条件
[options.hooks=true]Boolean在执行前/后创建钩子
[options.individualHooks=false]Boolean在执行前/后为每个实例创建钩子
[options.limit]Number要恢复的行数
[options.transaction]Transaction在事务中执行查询

3.27 update() - 更新记录

update(values, options) -> Promise.<Array.<affectedCount, affectedRows>>

更新所匹配的多个实例。promise回调中会返回一个包含一个或两个元素的数组,第一个元素始终表示受影响的行数,第二个元素表示实际影响的行(仅Postgreoptions.returning为true时受支持)

参数

名称类型说明
valuesObject
optionsObject
options.whereObject筛选条件
[options.fields]Array要更新字段,默认为全部
[options.validate=true]Boolean更新每条记录前进行验证
[options.hooks=true]Boolean在执行更新前/后创建钩子
[options.individualHooks=false]Boolean在执行更新前/后为每个实例创建钩子
[options.sideEffects=true]Boolean是否更新任何虚拟设置
[options.returning=false]Boolean返回受影响的行 (仅适用于 postgres)
[options.limit]Number要更新的行数 (仅适用于 mysql 和 mariadb)
[options.transaction]Transaction在事务中执行查询
[options.silent=false]Boolean如果为true,updatedAt字段将不会更新

3.28 describe() - 查询表信息

describe() -> Promise

运行一个表的描述查询,返回结果中将包含属性及其类型:

let User = sequelize.define('user', {
  firstName: Sequelize.STRING,
  lastName: Sequelize.STRING
});

User.describe().then(function(result){
  console.log(result);
})
// 结果如下
{ id: 
   { type: 'INT(11)',
     allowNull: false,
     defaultValue: null,
     primaryKey: true },
  firstName: 
   { type: 'VARCHAR(255)',
     allowNull: true,
     defaultValue: null,
     primaryKey: false },
  lastName: 
   { type: 'VARCHAR(255)',
     allowNull: true,
     defaultValue: null,
     primaryKey: false }
}