Sequelize官方中文文档 5. Instances - 实例

Sequelize官方GitHub:https://github.com/sequelize/sequelize
Sequelize官方中文文档:https://github.com/demopark/sequelize-docs-Zh-CN
Sequelize官方英文文档:http://docs.sequelizejs.com/

Instances - 实例

构建非持久性实例

为了创建定义类的实例,请执行以下操作。 如果你以前编写过 Ruby,你可能认识该语法。 使用 build - 该方法将返回一个未保存的对象,你要明确地保存它。

const project = Project.build({
  title: 'my awesome project',
  description: 'woot woot. this will make me a rich man'
})
 
const task = Task.build({
  title: 'specify the project idea',
  description: 'bla',
  deadline: new Date()
})

内置实例在定义时会自动获取默认值:

// 首先定义模型
const Task = sequelize.define('task', {
  title: Sequelize.STRING,
  rating: { type: Sequelize.STRING, defaultValue: 3 }
})
 
// 现在实例化一个对象
const task = Task.build({title: 'very important task'})
 
task.title  // ==> 'very important task'
task.rating // ==> 3

要将其存储在数据库中,请使用 save 方法并捕获事件(如果需要):

project.save().then(() => {
  // 回调
})
 
task.save().catch(error => {
  // 呃
})
 
// 还可以使用链式构建来保存和访问对象:
Task
  .build({ title: 'foo', description: 'bar', deadline: new Date() })
  .save()
  .then(anotherTask => {
    // 您现在可以使用变量 anotherTask 访问当前保存的任务
  })
  .catch(error => {
    // Ooops,做一些错误处理
  })

创建持久性实例

虽然使用 .build() 创建的实例需要显式的 .save() 调用来存储到 database 中;
.create() 完全省略了这个要求,一旦调用就自动存储实例的数据。

Task.create({ title: 'foo', description: 'bar', deadline: new Date() }).then(task => {
  // 你现在可以通过变量 task 来访问新创建的 task
})

也可以通过 create 方法定义哪些属性可以设置。 如果你创建基于可由用户填写的表单的数据库条目,这将非常方便。 例如,使用这种方式,你可以限制 User 模型,仅设置 username 和 address,而不是 admin 标志:

User.create({ username: 'barfooz', isAdmin: true }, { fields: [ 'username' ] }).then(user => {
  // 我们假设 isAdmin 的默认值为 false:
  console.log(user.get({
    plain: true
  })) // => { username: 'barfooz', isAdmin: false }
})

更新 / 保存 / 持久化一个实例

现在可以更改一些值并将更改保存到数据库...有两种方法可以实现:

// 方法 1
task.title = 'a very different title now'
task.save().then(() => {})
 
// 方法 2
task.update({
  title: 'a very different title now'
}).then(() => {})

通过传递列名数组,调用 save 时也可以定义哪些属性应该被保存。 当您基于先前定义的对象设置属性时,这是有用的。 例如。 如果您通过Web应用程序的形式获取对象的值。 此外,这在 update 内部使用。 它就像这样:

task.title = 'foooo'
task.description = 'baaaaaar'
task.save({fields: ['title']}).then(() => {
 // title 现在将是 “foooo”,而 description 与以前一样
})
 
// 使用等效的 update 调用如下所示:
task.update({ title: 'foooo', description: 'baaaaaar'}, {fields: ['title']}).then(() => {
 //  title 现在将是 “foooo”,而 description 与以前一样
})

当你调用 save而不改变任何属性的时候,这个方法什么都不执行。

销毁 / 删除持久性实例

创建对象并获得对象的引用后,可以从数据库中删除它。 相关的方法是 destroy

Task.create({ title: 'a task' }).then(task => {
  // 获取到 task 对象...
  return task.destroy();
}).then(() => {
 // task 对象已被销毁
})

如果 paranoid 选项为 true,则不会删除该对象,而将 deletedAt 列设置为当前时间戳。 要强制删除,可以将 force: true 传递给 destroy 调用:

task.destroy({ force: true })

批量操作(一次创建,更新和销毁多行)

除了更新单个实例之外,你还可以一次创建,更新和删除多个实例。 调用你需要的方法

  • Model.bulkCreate
  • Model.update
  • Model.destroy

由于你使用多个模型,回调将不会返回DAO实例。 BulkCreate将返回一个模型实例/DAO的数组,但是它们不同于create,没有 autoIncrement 属性的结果值. updatedestroy 将返回受影响的行数。

首先看下 bulkCreate

User.bulkCreate([
  { username: 'barfooz', isAdmin: true },
  { username: 'foo', isAdmin: true },
  { username: 'bar', isAdmin: false }
]).then(() => { // 注意: 这里没有凭据, 然而现在你需要...
  return User.findAll();
}).then(users => {
  console.log(users) // ... 以获取 user 对象的数组
})

一次更新几行:

Task.bulkCreate([
  {subject: 'programming', status: 'executing'},
  {subject: 'reading', status: 'executing'},
  {subject: 'programming', status: 'finished'}
]).then(() => {
  return Task.update(
    { status: 'inactive' }, /* 设置属性的值 */
    { where: { subject: 'programming' }} /* where 规则 */
  );
}).spread((affectedCount, affectedRows) => {
  // .update 在数组中返回两个值,因此我们使用 .spread
  // 请注意,affectedRows 只支持以 returning: true 的方式进行定义
  
  // affectedCount 将会是 2
  return Task.findAll();
}).then(tasks => {
  console.log(tasks) // “programming” 任务都将处于 “inactive” 状态
})

然后删除它们:

Task.bulkCreate([
  {subject: 'programming', status: 'executing'},
  {subject: 'reading', status: 'executing'},
  {subject: 'programming', status: 'finished'}
]).then(() => {
  return Task.destroy({
    where: {
      subject: 'programming'
    },
    truncate: true /* 这将忽 where 并用 truncate table 替代  */
  });
}).then(affectedRows => {
  // affectedRows 将会是 2
  return Task.findAll();
}).then(tasks => {
  console.log(tasks) // 显示 tasks 内容
})

如果您直接从 user 接受值,则限制要实际插入的列可能会更好。bulkCreate() 接受一个选项对象作为第二个参数。 该对象可以有一个 fields 参数(一个数组),让它知道你想要明确构建哪些字段

User.bulkCreate([
  { username: 'foo' },
  { username: 'bar', admin: true}
], { fields: ['username'] }).then(() => {
  // admin 将不会被构建
})

bulkCreate 最初是成为 主流/快速 插入记录的方法,但是有时您希望能够同时插入多行而不牺牲模型验证,即使您明确地告诉 Sequelize 去筛选哪些列。 你可以通过在options对象中添加一个 validate: true 属性来实现。

const Tasks = sequelize.define('task', {
  name: {
    type: Sequelize.STRING,
    validate: {
      notNull: { args: true, msg: 'name cannot be null' }
    }
  },
  code: {
    type: Sequelize.STRING,
    validate: {
      len: [3, 10]
    }
  }
})
 
Tasks.bulkCreate([
  {name: 'foo', code: '123'},
  {code: '1234'},
  {name: 'bar', code: '1'}
], { validate: true }).catch(errors => {

  /* console.log(errors) 看起来像这样:
  [
    { record:
    ...
    name: 'SequelizeBulkRecordError',
    message: 'Validation error',
    errors:
      { name: 'SequelizeValidationError',
        message: 'Validation error',
        errors: [Object] } },
    { record:
      ...
      name: 'SequelizeBulkRecordError',
      message: 'Validation error',
      errors:
        { name: 'SequelizeValidationError',
        message: 'Validation error',
        errors: [Object] } }
  ]
  */
  
})

一个实例的值

如果你记录一个实例,你会注意到有很多额外的东西。 为了隐藏这些东西并将其减少到非常有趣的信息,您可以使用 get 属性。 使用选项 plain: true 调用它将只返回一个实例的值。

Person.create({
  name: 'Rambow',
  firstname: 'John'
}).then(john => {
  console.log(john.get({
    plain: true
  }))
})
 
// 结果:
 
// { name: 'Rambow',
//   firstname: 'John',
//   id: 1,
//   createdAt: Tue, 01 May 2012 19:12:16 GMT,
//   updatedAt: Tue, 01 May 2012 19:12:16 GMT
// }

提示: 您还可以使用 JSON.stringify(instance) 将一个实例转换为 JSON。 基本上与 values 返回的相同。

重载实例

如果你需要让你的实例同步,你可以使用 reload 方法。 它将从数据库中获取当前数据,并覆盖调用该方法的模型的属性。

Person.findOne({ where: { name: 'john' } }).then(person => {
  person.name = 'jane'
  console.log(person.name) // 'jane'
 
  person.reload().then(() => {
    console.log(person.name) // 'john'
  })
})

递增

为了增加实例的值而不发生并发问题,您可以使用 increment

首先,你可以定义一个字段和要添加的值。

User.findById(1).then(user => {
  return user.increment('my-integer-field', {by: 2})
}).then(user => {
  // Postgres默认会返回更新的 user (除非通过设置禁用 { returning: false })
  // 在其他方言中,您将需要调用 user.reload() 来获取更新的实例...
})

然后,你可以定义多个字段和要添加到其中的值。

User.findById(1).then(user => {
  return user.increment([ 'my-integer-field', 'my-very-other-field' ], {by: 2})
}).then(/* ... */)

最后,你可以定义一个包含字段及其递增值的对象。

User.findById(1).then(user => {
  return user.increment({
    'my-integer-field':    2,
    'my-very-other-field': 3
  })
}).then(/* ... */)

递减

为了减少一个实例的值而不遇到并发问题,你可以使用 decrement

首先,你可以定义一个字段和要添加的值。

User.findById(1).then(user => {
  return user.decrement('my-integer-field', {by: 2})
}).then(user => {
  // Postgres默认会返回更新的 user (除非通过设置禁用 { returning: false })
  // 在其他方言中,您将需要调用 user.reload() 来获取更新的实例...
})

然后,你可以定义多个字段和要添加到其中的值。

User.findById(1).then(user => {
  return user.decrement([ 'my-integer-field', 'my-very-other-field' ], {by: 2})
}).then(/* ... */)

最后, 你可以定义一个包含字段及其递减值的对象。

User.findById(1).then(user => {
  return user.decrement({
    'my-integer-field':    2,
    'my-very-other-field': 3
  })
}).then(/* ... */)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352