前言:
Sequelize中提供的增删改查相关的函数都能转成原生的sql语句。本篇文章介绍一个不是很常见但是有时候批量插入很方便的函数——bulkCreate。
bulkCreate讲解
官方文档理解
bulkCreate() - 创建多条记录
bulkCreate(records, [options]) -> Promise.<Array.<Instance>>
复制代码
批量创建并保存多个实例。
处理成功后,会在回调函数中返回一个包含多个实例的数组。
参数
名称 | 类型 | 说明 |
---|---|---|
records | Array | 要创建实例的对象(键/值 对)列表 |
[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 | 在事务中执行查询 |
注意:options.updateOnDuplicate参数中的行键已存在我的理解是:数据库表中现有的记录的唯一索引或者主键如果已经存在,执行更新操作
对应原生sql语句讲解
在MySQL数据库中,如果在insert语句后面带上ON DUPLICATE KEY UPDATE 子句。
- 要插入的行与表中现有记录的惟一索引或主键中产生重复值,那么就会发生旧行的更新;
- 如果插入的行数据与现有表中记录的唯一索引或者主键不重复,则执行新纪录插入操作。
await CompositionAnswer.bulkCreate(answerList, { updateOnDuplicate: ['answer', 'updatedAt'] })
以上代码可以实现插入多个数据时,若其中有重复的数据,只对 answer和updatedAt进行更新。
那么关键来了,怎么判定数据重复,如果我不想使用表的默认主键(比如id),怎么办?
答案就是 ,设置unique索引!!!
static options = {
indexes: [
{
name: 'composition_answer_index',
fields: [ 'exercise_id' ]
},
{
name: 'composition_answer_index_unique',
unique: true,
fields: ['exercise_id', 'question_id', 'question_material_id']
}
]
}
static init (sequelize) {
super.init({
sequelize,
attributes: this.attributes,
tableName: 'composition_answer',
options: this.options
})
}
composition_answer_index_unique 就是我们的唯一索引,当出现重复的数据时,不会进行插入,而是更新。
但是sequelize对于uniqueKeys设置有bug(目前最新版本6.2.3),只到上边那一步时,bulkCreate时还是没有识别到唯一索引。
hack方式就是,在attributes的字段,设置上 索引名称。
static attributes = {
exerciseId: {
unique: 'composition_answer_index_unique', //就是他!!!
type: DataTypes.INTEGER,
field: 'exercise_id'
},
questionId: {
unique: 'composition_answer_index_unique', // 和他!!!
type: DataTypes.INTEGER,
field: 'question_id'
},
questionMaterialId: {
unique: 'composition_answer_index_unique', // 还有他!!!
type: DataTypes.INTEGER,
field: 'question_material_id',
allowNull: true
}
}